面灵AI→

乐享元游 数据开发 一面:数仓分层、大表 Join 与指标异常排查

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

经历与项目

  1. 先做个自我介绍吧。
  2. 我看到你简历里有竞赛经历模块,挑一个含金量最高的,讲一下你主要负责的部分。
  3. 你刚才提到数据质量运营这段实习,你觉得这份工作和另外两段数据开发实习有哪些差别?
  4. 那你当时为什么投这个运营相关的实习?

数仓与建模

  1. 你刚才说从分层到看板整条链路都接触过,那讲一下 ODS、DWD、DWS、ADS 每一层的职责。
  2. 在项目里面,你觉得比较复杂、印象比较深的是什么?讲一下。
  3. 那这个任务每日的数据增量大概是多少?
  4. 那任务运行时长这块呢?
  5. 重新讲一下这个案例里的性能优化具体怎么做的。
  6. 做 join 的时候,比如 DWD 层和部门维度表 join,会遇到大表 join 场景,这种情况你怎么处理?
  7. 全量同步一般什么场景会触发?
  8. 你重新说一遍分区和分桶是怎么做的?
  9. 那分桶的数量怎么定?
  10. 简历提到每周小文件合并,讲一下什么是小文件、合并过程、产生原因。

技术栈与引擎

  1. 讲一下你的各个技术栈,在实习工作里分别用在哪些地方。
  2. Spark 这边,提交一条 Spark SQL,任务实际运行有哪些过程?
  3. 你用过 Hive,了解 Hive 底层文件层的文件结构吗?
  4. 之前用过 MySQL 吗?
  5. 了解 Iceberg 和 MySQL 的区别吗?
  6. 同一行数据,在 Iceberg 里的存储和 MySQL 里的存储有什么区别?
  7. Flink 你用到什么程度?

场景与反问

  1. 前面提到数据看板,如果看板指标昨天是 3%,今天突涨到 6%,任务本身没有报错,你怎么排查是真实上涨还是数据异常?
  2. 上线后发现 bug,同时业务又有改动需求,你怎么处理?
  3. 聊一下你使用 AI 到什么程度?
  4. 补充问一下,ODS 到 ADS 每一层的数据存在什么存储里?
  5. 是自建平台,还是托管在腾讯云这类云厂商?
  6. 反问:这个岗位归属游戏业务,日常工作内容、团队规模、是否会分配到单独业务项目组?团队内部 AI 的使用情况、主要用途、频率和对 AI 开发的态度?

《参考解析》

四层数仓的职责要按“数据形态 + 使用对象”讲,别只背名字。 ODS 是贴源层,保留原始日志、业务库同步数据和少量清洗,按日期或业务线分区,主要用于追溯和重跑,一般不做复杂加工;DWD 是明细层,做清洗、去重、字段标准化、维度退化,把同一业务过程的事实统一成一张明细表,是口径的基准;DWS 是汇总层,按主题和维度做轻度聚合,形成宽表,供跨业务复用,避免每个看板都从明细重算;ADS 是应用层,直接面向报表、看板、接口,指标已经算好,通常同步到 MySQL、ClickHouse、Doris 或 ES 这类 OLAP/查询存储。物理存储不必和逻辑分层一一对应:ODS、DWD、DWS 多数放在 HDFS/对象存储上的 Hive 或 Iceberg 表里,ADS 可能在湖仓里也可能导出到 serving 层。回答时要补一句“分层是为了复用和隔离变更,不是文件目录越多越好”,并说明每一层的更新频率、保留周期和负责人。

大表 join 先判断“能不能不 join”,再谈广播、分桶和打散。 如果右表是部门这类小维表,直接 broadcast/map join,把维表放进每个 executor 的内存,避免 shuffle;Hive 可用 /*+ MAPJOIN(dim) */,Spark 用 broadcast() 或让 AQE 自动选。两张大表 join 时,优先做分区裁剪、列裁剪、谓词下推,减少参与 shuffle 的数据;如果两表已经按同一 key 分桶且桶数相同,可以用 bucket map join / SMB join,把 join 变成桶内归并,省掉 shuffle,但要求写入时就按这个分布组织。热点 key 导致的倾斜,用加盐打散:给大表热点 key 加随机前缀、小表对应膨胀,聚合后再去前缀;或者把热点 key 单独抽出来广播/单独处理。维表也可以外置到 Redis,在流式场景做 lookup join。全量同步一般发生在首次初始化、历史数据修复或回溯、源库没有可靠的增量标识(无 binlog/时间戳)、小维表每日全量覆盖、以及需要对账重建的场景;全量要限流、分片、断点续传,避免把源库打挂。

分区是“按目录裁数据”,分桶是“按 hash 把数据切成固定文件”,小文件则是两者的共同副作用。 分区字段选低基数、常用的过滤维度,比如日期、业务线、地区,分区太多会产生大量小目录和小文件,动态分区写入时尤其明显。分桶是对分桶键做 hash 后对桶数取模,写入时直接落到固定编号的文件,好处是桶内 join、采样和稳定并行度;桶数按“总数据量 / 单文件目标大小”估,单文件一般控制在 128~256MB,桶数常取 2 的幂,方便扩容时只翻倍、减少重分布。小文件的产生原因包括:动态分区每个分区都写文件、reduce 数过多、频繁小批 insert、流式任务短 checkpoint、上游本身就是碎文件。合并手段有:控制 reduce/分区数、用 distribute by 让同键进同一 reducer、insert overwrite 重写整张表、Hive 的 concatenate 或 ORC/Parquet 合并、Iceberg 的 rewrite_data_files 和 rewrite_manifests、Spark 的 coalesce 与 AQE 合并 shuffle 分区。合并任务本身也要控输出文件大小,别从“很多小文件”变成“几个超大文件”。

一条 Spark SQL 要经过“解析—分析—优化—物理计划—调度执行”五段。 SQL 先被 parser 解析成抽象语法树,转成未解析的逻辑计划;analyzer 借助 catalog 解析表、列、函数和类型,得到已解析逻辑计划;Catalyst 优化器做谓词下推、列裁剪、常量折叠、join 重排、子查询展开等规则优化;SparkPlanner 把逻辑计划转成物理计划,并根据代价选择 join 策略和 shuffle 方式;prepareForExecution 插入 Exchange、确保分区和排序要求,然后 whole-stage codegen 生成可执行代码。运行时 DAG Scheduler 按宽窄依赖切 stage,Task Scheduler 把 task 分发到 executor,shuffle 阶段写 map 输出、拉 reduce 输入。AQE 会在运行时根据统计信息合并小分区、切换 broadcast join、处理倾斜。Flink 则按 job graph 拆成 operator chain,TaskManager 的 slot 执行,靠 checkpoint 和 state backend 做容错,watermark 处理乱序,exactly-once 依赖 checkpoint 与两阶段提交/sink 幂等。面试里不必把每个类名背全,但要把“哪里会发生 shuffle、哪里可能倾斜、AQE 能救什么”讲清楚。

Hive 的表是目录,MySQL 的表是 B+ 树;Iceberg 又在文件之上加了一层元数据。 Hive 一张表对应 HDFS 上的一个目录,分区是子目录(如 dt=2026-10-21),目录里是 ORC/Parquet/Text 文件;以 ORC 为例,文件由多个 stripe 组成,每个 stripe 里有索引、数据和 footer,footer 存统计信息和 schema;Parquet 则是 row group、column chunk、page 和 footer。MySQL 是行式存储,聚簇索引的叶子页直接放整行数据,二级索引叶子存主键,更新是原地改页并通过 undo/redo 保证事务和崩溃恢复。Iceberg 是“数据文件 + manifest + manifest list + metadata json”的湖仓表格式:metadata 记录 schema、分区规则和快照,manifest list 指向 manifest,manifest 里记录每个数据文件及其统计信息;更新一行不会原地改文件,而是写新数据文件加 delete file(Merge-on-Read),或者重写整个数据文件(Copy-on-Write),查询时按快照合并。所以同一行数据在 MySQL 里是“页内一行、可原地更新”,在 Iceberg 里是“列式文件中的一段、更新产生新文件或删除标记”。Iceberg 强在 schema 演进、隐藏分区、时间旅行和快照隔离,MySQL 强在点查、事务和低延迟写入,两者服务的是不同场景。

指标从 3% 涨到 6%,先查“这个数是怎么算出来的”,再查“业务上有没有理由”。 第一步做链路核对:分区有没有重复或缺失、任务有没有重跑/补数、上游埋点有没有改版本、维表 join 有没有膨胀、去重口径有没有变、时区和日期边界有没有错位、采样或过滤条件有没有动。第二步拆分子分母:比率翻倍可能是分子涨,也可能是分母跌,分别看 DAU、订单量、曝光量这些基数。第三步按维度拆:渠道、机型、地区、新老用户、业务线,看是全量上涨还是某个单点把均值拉高。第四步和业务侧交叉验证:当天有没有活动、发版、投放、政策变化,订单、支付、客服数据能不能对上。第五步看历史波动和统计口径:是全量数据还是抽样,波动是否超过历史同期区间。最后才下结论:真实上涨要能解释机制、能复现、能被独立数据源印证;数据异常要定位到具体表、任务、字段,并补数据质量规则(唯一性、非空、值域、波动阈值)和血缘告警。不要一看到涨就说“业务变好”,也不要把所有异常都归因于埋点。

线上 bug 和业务需求撞车时,先止血、再分级、最后谈排期。 先评估影响面:多少用户、是否影响资金/订单/合规、有没有替代路径;能回滚就回滚,不能回滚就加开关或热修,先保留现场日志和复现条件。修复走最小改动,补回归测试,灰度发布并盯监控。业务需求单独评估优先级,不要借修 bug 的紧急通道夹带需求,也不要在故障未止血时讨论新功能;如果需求能缓解问题(比如关掉某个入口),可以作为临时措施,但要记录并事后补正式方案。事后复盘要落到根因、测试缺口、监控缺口和行动项,避免同类问题再发。AI 的使用可以讲得具体:用 AI 辅助写 SQL、解释执行计划、生成边界测试、归纳日志和排查思路,但结果必须自己验证,敏感数据要脱敏,AI 生成的代码要过 review 和测试;把它当加速器,不当正确性来源。