乐享元游 数据开发 一面:数仓分层、大表 Join 与指标异常排查
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
经历与项目
- 先做个自我介绍吧。
- 我看到你简历里有竞赛经历模块,挑一个含金量最高的,讲一下你主要负责的部分。
- 你刚才提到数据质量运营这段实习,你觉得这份工作和另外两段数据开发实习有哪些差别?
- 那你当时为什么投这个运营相关的实习?
数仓与建模
- 你刚才说从分层到看板整条链路都接触过,那讲一下 ODS、DWD、DWS、ADS 每一层的职责。
- 在项目里面,你觉得比较复杂、印象比较深的是什么?讲一下。
- 那这个任务每日的数据增量大概是多少?
- 那任务运行时长这块呢?
- 重新讲一下这个案例里的性能优化具体怎么做的。
- 做 join 的时候,比如 DWD 层和部门维度表 join,会遇到大表 join 场景,这种情况你怎么处理?
- 全量同步一般什么场景会触发?
- 你重新说一遍分区和分桶是怎么做的?
- 那分桶的数量怎么定?
- 简历提到每周小文件合并,讲一下什么是小文件、合并过程、产生原因。
技术栈与引擎
- 讲一下你的各个技术栈,在实习工作里分别用在哪些地方。
- Spark 这边,提交一条 Spark SQL,任务实际运行有哪些过程?
- 你用过 Hive,了解 Hive 底层文件层的文件结构吗?
- 之前用过 MySQL 吗?
- 了解 Iceberg 和 MySQL 的区别吗?
- 同一行数据,在 Iceberg 里的存储和 MySQL 里的存储有什么区别?
- Flink 你用到什么程度?
场景与反问
- 前面提到数据看板,如果看板指标昨天是 3%,今天突涨到 6%,任务本身没有报错,你怎么排查是真实上涨还是数据异常?
- 上线后发现 bug,同时业务又有改动需求,你怎么处理?
- 聊一下你使用 AI 到什么程度?
- 补充问一下,ODS 到 ADS 每一层的数据存在什么存储里?
- 是自建平台,还是托管在腾讯云这类云厂商?
- 反问:这个岗位归属游戏业务,日常工作内容、团队规模、是否会分配到单独业务项目组?团队内部 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 和测试;把它当加速器,不当正确性来源。