拓冰建站拓冰建站
首页 / 资讯中心 / 正文

数据开发每日面试题 Day3

1SQL计算次日留存率来源自拟高频题难度★★★☆☆表user_login(user_id,login_date)求每天登录用户的次日留存率当天登录的用户中有多少人在第二天再次登录核心考察点自连接、日期计算、去重、指标口径。推荐解法先去重因为同一个用户一天可能登录很多次WITHlogin_distinctAS(SELECTDISTINCTuser_id,login_dateFROMuser_login),retentionAS(SELECTa.login_date,COUNT(DISTINCTa.user_id)ASactive_users,COUNT(DISTINCTb.user_id)ASretained_usersFROMlogin_distinct aLEFTJOINlogin_distinct bONa.user_idb.user_idANDb.login_dateDATE_ADD(a.login_date,INTERVAL1DAY)GROUPBYa.login_date)SELECTlogin_date,active_users,retained_users,retained_users*1.0/active_usersASretention_rateFROMretention;面试口述我会先按照 user_id 和 login_date 去重然后把当天登录记录和第二天登录记录按照用户 ID 进行LeftJoin。分母是当天去重活跃用户数分子是能够匹配到第二天登录记录的用户数。一个非常容易忽略的问题面试官可能问“9 月 7 日的数据还没完整结束你能计算 9 月 7 日次留吗”不能。因为9月7日用户 ↓ 需要观察9月8日所以指标存在观察窗口完整性问题。这就是数据分析/数仓里经常说的指标不仅要 SQL 正确还要口径和数据周期正确。追问7 日留存怎么算Join 条件改成b.login_dateDATE_ADD(a.login_date,INTERVAL7DAY)注意这通常表示“第 7 日留存”不等同于“7 天内任意一天回来”。2MySQL事务的四个特性是什么真正难的是哪两个来源自拟高频题难度★★★☆☆ACIDAtomicity 原子性 Consistency 一致性Isolation隔离性 Durability 持久性不要只背中文。Atomicity事务要么全部成功要么全部失败例如转账A-100B100不能只执行第一步。Consistency事务执行前后 数据必须满足定义好的业务约束。例如总金额不能凭空改变。注意Consistency 并不是单纯由数据库自动保证的。业务逻辑、约束设计同样参与保证一致性。Isolation并发事务之间不能产生不可接受的相互干扰。典型问题脏读 不可重复读 幻读 Durability事务一旦 Commit即使数据库随后崩溃也应该能够恢复。通常依赖Redo Log WAL等机制。追问Undo Log 和 Redo Log 区别可以先这么理解Undo → 怎么回到以前 Redo → 怎么恢复已经提交的修改Undo 还与 MVCC 的历史版本读取密切相关。3MVCC 到底解决了什么问题来源自拟高频题难度★★★★☆核心问题数据库里同时发生读写最简单的办法是什么全部加锁。但这样并发性能很差。MVCCMulti-Version Concurrency Control多版本并发控制。核心思想同一条数据可以存在多个逻辑版本让读事务根据自己的可见性规则读取合适版本而不是所有读写都互相阻塞。例如事务 A读取 balance 100事务 BUPDATEbalance200;COMMIT;事务 A 在某些隔离级别下仍可能继续看到100而不是突然变成200因为它读取的是符合自己 Read View 的历史版本。MySQL InnoDB 中常涉及Undo LogReadView隐藏事务版本信息面试不要说“MVCC 就是不加锁。”不准确。数据库仍然存在行锁 间隙锁Next-KeyLock等锁机制。更准确MVCC 主要减少读写之间的锁竞争提高并发读取能力但并不意味着数据库完全不需要锁。4HDFS 为什么适合大文件不适合海量小文件来源自拟高频题难度★★★☆☆这是 Hadoop 高频基础题。HDFSHadoop Distributed File System。它把文件拆成Block分散存储在 DataNode。NameNode 维护文件名 目录 Block映射 副本位置 权限等元数据关键来了这些元数据主要维护在 NameNode 内存中。假设1TB如果是几个 GB 级的大文件对应的文件和 Block 元数据数量相对有限。但如果变成1亿个10KB 文件总数据量可能没多大但文件数量 Block数量 元数据数量爆炸。NameNode 压力巨大。小文件还有另一个问题Spark/Hive 读取大量小文件时会产生大量文件打开 大量 Task 大量调度开销计算效率也会下降。怎么处理常见小文件合并 合理控制 Reduce 数量 调整写入并行度 Compaction 使用 SequenceFile 等聚合方式现代数据湖表格式也通常存在 Compaction 机制。追问小文件是不是因为浪费 Block 空间不要这么回答。一个 1 MB 文件使用 128 MB Block并不意味着物理磁盘一定浪费 127 MB。真正主要的问题是元数据数量和计算调度开销。5Hive 分区和分桶到底有什么区别来源自拟高频题难度★★★☆☆很多人会说分区是大分类分桶是小分类。不够。Partition通常直接体现在目录/orders/dt20260905//orders/dt20260906//orders/dt20260907/查询WHEREdt20260907可以直接跳过其他目录。核心价值PartitionPruning减少需要读取的数据。Bucket分桶通常根据字段 Hashhash(user_id)%N决定记录进入哪个 Bucket。例如bucket_000 bucket_001 bucket_002 bucket_003核心价值更偏向数据组织 抽样Join优化 并行处理 最大区别分区根据分区条件直接排除整个数据目录。分桶一个分区内部进一步按照Hash等规则组织数据。追问user_id 适合做分区字段吗如果有几千万用户通常非常不适合。可能制造几千万个分区元数据和目录管理直接爆炸。日期这种dtmonthregion通常更适合作为有限基数的分区字段。6SparkBroadcast Join 为什么能减少 Shuffle来源自拟高频题难度★★★☆☆假设订单表500GB 城市维度表5MB普通 JoinOrders ──Shuffle──┐ ├─JoinCity ──Shuffle──┘为了让相同 Join Key 到同一 Executor需要重新分区。BroadcastJoin ┌→ Executor1City ────┼→ Executor2└→ Executor3Orders 保持原分区把 5 MB 城市表复制到每个 Executor。每个 Executor在本地直接 Join 大表当前分区。于是大表不需要按照 Join Key Shuffle。优势通常可以显著减少网络传输 磁盘 Spill Shuffle Sort风险如果你广播5GB可能导致Executor OOM GC 网络压力所以BroadcastJoin的关键前提是被广播侧足够小。追问为什么昨天讲 Hive MapJoin今天 Spark 又叫 Broadcast Join核心思想非常相似把小表放到计算节点本地避免大表 Shuffle。只是不同执行引擎的实现和术语有所差异。7Kafka Offset 到底是什么它存在 Broker 还是 Consumer来源自拟高频题难度★★★☆☆假设 Partitionoffset0→ message A1→ message B2→ message C3→ message DOffset 消息在Partition中的逻辑位置。注意Offset是Partition级别的。不是整个 Topic 一个统一 offset。Consumer 还会维护自己的消费进度例如GroupA P0 →100P1 →230GroupB P0 →20P1 →80两个 Consumer Group可以独立消费同一个 Topic。现代 Kafka 通常把 Consumer Group 提交的 Offset 存储在 Kafka 内部主题__consumer_offsets所以“Offset 在 Broker 还是 Consumer”这种问法本身有点偷换概念消息本身在Partition中有offset Consumer 本地运行时维护当前消费位置Group提交后的消费进度由 Kafka 协调和持久化。追问Consumer 重启怎么知道从哪继续 读取 ConsumerGroup已提交的Offset。8Flink Backpressure 是什么怎么产生的来源自拟高频题难度★★★★☆假设Kafka Source ↓100,000msg/s Map ↓ Window ↓ Doris SinkDoris Sink 只能处理20,000msg/s数据会逐渐积压。下游处理不过来Sink ↑ Window ↑ Map ↑ Source压力向上游传播。这就是Backpressure反压。常见原因Sink 写入慢 外部数据库性能下降 某算子计算复杂 数据倾斜 网络瓶颈 并行度不足 GC严重怎么排查看Flink Web UI 各 Operator 吞吐 BusyTimeBackpressure 各 Subtask 数据量Checkpoint时间 Sink 延迟如果Sink100%busy上游持续 Backpressure优先调查 Sink。如果只有一个 Subtask 特别忙怀疑数据倾斜。怎么优化根据瓶颈增加并行度 批量写 异步 I/O 优化外部系统 重新设计Key降低单条处理成本不要直接“反压就加并行度。”外部数据库已经顶满时再加 Sink 并行度可能让它死得更快。9Redis缓存穿透、击穿、雪崩有什么区别来源自拟高频题难度★★★★☆这三个特别容易混。缓存穿透查询根本不存在的数据例如攻击者不断请求user_id-99999999Redis 没有↓ DB 查询 ↓ 也没有每次都穿过缓存。解决缓存空值 Bloom Filter 参数校验缓存击穿某一个超级热点Key突然过期。例如双十一商品信息瞬间10万请求 ↓ Redis Miss ↓ 全部打 DB解决互斥锁 逻辑过期 热点Key不同时失效 提前刷新缓存雪崩大量 Key同一时间失效或者 Redis 整体不可用。于是大量请求 ↓ DB ↓ 数据库崩解决TTL随机化 Redis高可用 限流 熔断 多级缓存一句话记忆穿透查不存在的 击穿一个热点没了 雪崩一大片都没了这个直接背。10Doris 的 Duplicate / Unique / Aggregate Key 怎么选来源自拟高频题难度★★★★☆这是今天专门给你的 Mini Data Platform 链路加的一题。以 Apache Doris 为例不同数据模型对应不同业务语义。Duplicate Key保留明细。例如订单事件order_id user_id amount create_time 如果希望每条明细都保留DuplicateKey。适合日志 流水 明细事实Unique Key同一个业务 Key最终保留一个最新逻辑版本。例如order_id1001statusCREATED之后order_id1001statusPAID希望查询结果看到PAID这类 Upsert 场景更适合 Unique Key。CDC 链路尤其常见。Aggregate Key按照 Key提前聚合 Value。例如date,city →SUM(sales)适合固定维度的聚合分析。面试追问MySQL CDC → Flink → Doris 的订单状态表你选哪个如果需要根据order_id持续更新订单最新状态Unique Key通常更符合业务语义。如果是不可变订单事件流水Duplicate Key 更自然。关键不是背模型而是先看数据是否更新再看查询需要明细还是预聚合。11DolphinScheduler 里上游失败下游应该怎么处理补数又怎么做来源结合生产调度场景自拟难度★★★★☆正常 DAGODS ↓ DWD ↓ DWS ↓ ADS如果DWD失败原则上依赖 DWD 的 DWS/ADS 不应该继续跑。否则旧数据新日期可能产生看似正常、实际上错误的结果。修复以后怎么办假设2026-09-06DWD 失败。修复代码后重跑 DWD20260906↓ 质量检查 ↓ 重跑受影响 DWS ↓ 重跑 ADS而不是把今天所有任务全部重新跑一遍。应该根据DAG依赖 数据日期 影响范围确定最小重跑范围。一个非常重要的设计ETL 最好支持业务日期参数例如python job.py--biz_date 2026-09-06而不是代码里永远today-1为什么因为后者非常难补历史数据。面试口述我倾向于让离线任务显式接收业务日期参数使任务逻辑和实际运行日期解耦。这样生产失败或需要历史回刷时可以针对指定分区重跑而不需要修改代码中的日期逻辑。12银行数仓为什么会用存储过程替代部分 Kettle 转换面试官看到“编写存储过程替代 Kettle”非常可能问为什么要替代Kettle 不好吗千万不要回答“因为存储过程比较快。”太绝对。推荐回答结构首先说明Kettle 和存储过程各有适用场景并不是谁一定优于谁。Kettle 优势可视化 多数据源连接 流程编排 ETL组件丰富但如果某段逻辑主要是同数据库内部 大量SQL转换Join聚合Insert/Update那么把数据数据库 ↓ Kettle ↓ 数据库反复搬运可能增加网络传输 ETL引擎处理 维护复杂度如果直接由 DB2/GBase 内部存储过程数据就地处理可以利用数据库自己的优化器 索引 并行执行 事务能力某些场景下性能和稳定性会更合适。但是存储过程也有缺点数据库耦合高 代码可读性可能下降 版本管理困难 复杂逻辑难测试 迁移成本所以真正成熟的回答是是否使用存储过程要根据数据量、数据是否跨源、逻辑复杂度、数据库能力以及维护成本综合判断而不是认为存储过程天然优于 ETL 工具。追问如果让你现在重新设计还会全部用存储过程吗答不会。我会把数据库内部适合set-basedSQL处理的逻辑保留在数据库侧而跨数据源同步、工作流编排和需要更强可观测性的流程交给 ETL/调度系统避免把所有业务逻辑都塞进存储过程。13场景题MySQL → CDC → Kafka → Flink → Doris发现 Doris 少了 2% 订单怎么查来源结合实时链路自拟难度★★★★★今天最重要的场景题。链路MySQL ↓ CDC ↓ Kafka ↓ Flink ↓ Doris业务说MySQL 今天 100 万订单Doris 只有 98 万。不要第一反应Kafka 丢消息了。这是非常不成熟的排查方式。第一层先确认口径先确认100万和98万是不是同一时间范围 是否包含删除记录 是否按照create_time还是update_time 是否包含测试订单 Doris查的是明细还是最终状态很多“数据丢失”其实是口径不一致。第二层建立各节点计数不要盯着最终结果猜。应该检查MySQL100万 ↓ CDC ? ↓ Kafka ? ↓ Flink Input ? ↓ Flink Output ? ↓ Doris98万找到数据从哪一段开始减少。第三层CDC检查Binlog位置 Connector状态 重启记录Schema变更 过滤规则Snapshot增量切换第四层Kafka检查TopicPartition生产数量 Consumer LagOffset错误日志如果 Kafka 已经有完整事件问题就不是 MySQL → Kafka。第五层Flink检查输入条数 输出条数 Filter 异常记录 反压Checkpoint重启 状态 Side Output尤其注意代码有没有ifcondition:return把部分订单过滤掉。第六层Doris检查LoadJob RejectedRowsSchema数据类型UniqueKey导入错误Duplicate/Upsert这里有一个非常阴险的情况。MySQL100万 CDC事件并不一定意味着 Doris100万行如果 Doris 是Unique Key(order_id)而同一个订单发生CREATEPAID SHIPPEDMySQL CDC 产生3个事件Doris 最终可能只有1条订单所以事件数量 ≠ 最终状态表行数。这就是为什么第一步必须先确认口径。面试口述可以练成我不会直接假设是某个组件丢数据而会先确认源端和目标端的统计口径是否一致然后沿数据链路逐层建立可对账的数量指标定位数据从哪个节点开始出现差异。如果 Kafka 中数据完整就排除上游 CDC如果 Flink 输入完整但输出减少则检查过滤逻辑、异常数据和状态处理如果 Flink 输出完整则进一步检查 Doris 的导入错误、Reject、Schema 以及数据模型。尤其对于 CDC 链路还需要区分变更事件数量和最终业务实体数量因为 Unique Key Upsert 会合并同一个业务 Key 的多个变更事件。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门