数据工程师面试考察三件事:SQL、你如何设计和运行数据管道,以及你如何思考规模与故障。下面是 20 道题及参考答案,你可以按需调整,顺序按照候选人通常遇到的顺序排列。SQL 示例在发布前已在小型示例数据库上运行过,展示的结果是真实输出。
SQL 问题
1. 找出每家公司或整体中第二高的薪资
使用 DENSE_RANK,这样并列的薪资共享同一排名,“第二高”指第二个不同的值。
SELECT name, salary
FROM (
SELECT name, salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS r
FROM employees
) t
WHERE r = 2;
在薪资为 150、130、130、110、90、70 的表上,这会返回两位薪资为 130 的人。说明你为什么选择 DENSE_RANK 而不是 RANK(并列后会跳号)和 ROW_NUMBER(会任意打破并列)。
2. 每个部门薪资最高的两名员工
SELECT dept, name, salary
FROM (
SELECT dept, name, salary,
RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS r
FROM employees
) t
WHERE r <= 2;
PARTITION BY 会为每个部门重新开始排名。提一下,薪资并列时用 RANK 可能返回超过两行。
3. 每个客户的累计总额
SELECT customer, order_date, amount,
SUM(amount) OVER (PARTITION BY customer ORDER BY order_date) AS running_total
FROM orders;
对于日期递增、订单金额为 10、20、30 的客户,累计总额分别是 10、30、60。
4. 删除重复行,保留第一行
SELECT id, user_id
FROM (
SELECT id, user_id,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY id) AS rn
FROM events
) t
WHERE rn = 1;
这里用 ROW_NUMBER 是对的,因为你想每组只保留一行。准备好回答在真实表中你如何决定保留哪条重复记录(最新时间戳、最完整的记录)。
5. 与上一行的差值
SELECT order_date, amount,
amount - LAG(amount) OVER (ORDER BY order_date) AS change
FROM orders
WHERE customer = 'A';
第一行的差值是 NULL,因为没有上一行。把这一点说出来,因为这通常是后续追问。
6. WHERE 和 HAVING 有什么区别?
WHERE 在分组前过滤行,HAVING 在聚合后过滤分组。你不能在 WHERE 中使用 COUNT(*) 这样的聚合函数。
7. 如何优化慢查询?
- 在改动任何东西之前先看查询计划。
- 检查过滤条件能否用上索引,以及列上的函数是否阻止了索引使用。
- 减少扫描的数据量:只选需要的列,尽早过滤,对大表按日期分区。
- 用连接或公共表表达式替换重复的子查询,并检查连接中是否意外产生了行数膨胀。
- 对于数据仓库,检查聚簇键或排序键,以及每个查询读取了多少数据。
管道设计问题
8. ETL 还是 ELT?
ETL 在加载前转换数据。ELT 先加载原始数据,然后在仓库内转换。ELT 在云数据仓库中很常见,因为存储便宜,原始数据保留下来可供重新处理,转换可以以 SQL 形式进行版本管理。当数据必须在落地前清洗或脱敏时,比如移除个人数据,ETL 仍然有意义。
9. 批处理还是流处理?
根据数据需要多新鲜来选择。批处理更简单、更便宜,适合日报。流处理适合分钟或秒级重要的场景,比如欺诈检查或实时看板。很多系统两者都用。说清楚业务决策是什么,而不只是技术。
10. 什么是幂等管道,为什么它很重要?
运行两次的结果和运行一次相同。这很重要,因为任务会失败并重试。要让加载幂等,可以按分区写入并覆盖该分区,或者用稳定键做 upsert,这样重试不会产生重复。
11. 如何处理迟到或乱序的数据?
使用事件时间而不是到达时间,并定义数据最多能迟到多久。在流处理系统中,水位线告诉任务在关闭窗口前要等多久。对于批处理表,按计划重新处理最近的分区,或者保留一个修正流程来重写受影响的那几天。
12. 如何为故障和重试做设计?
让步骤小、幂等、可独立重跑。把状态存储在任务之外。不仅对错误告警,也对数据缺失或延迟告警。给重试设上限,把反复失败的任务送到有人查看的地方。
13. 如何检查数据质量?
| 检查项 | 示例 |
|---|---|
| 完整性 | 行数与源在容差范围内一致 |
| 唯一性 | 主键没有重复 |
| 有效性 | 值落在预期范围或集合内 |
| 新鲜度 | 最新时间戳足够新 |
| 一致性 | 相关表之间的总计一致 |
在管道内运行检查并尽早失败,这样坏数据不会进入报表。
建模与存储问题
14. 什么是星型模型?
一个中心事实表存储可度量的事件,比如订单,并连接到描述这些事件的维度表,比如客户、产品和日期。它查询简单,聚合速度快。雪花模型对维度做了进一步规范化,节省了空间,但增加了连接操作。
15. 什么是缓慢变化维度?
它们是随时间变化的维度属性,比如客户的地址。Type 1 直接覆盖旧值,丢失历史记录。Type 2 新增一行并带上开始和结束日期,从而保留历史。你要说明针对哪种属性会选择哪种方式,以及为什么。
16. 如何对大表进行分区?
选择大多数查询都会用来过滤的列进行分区,通常是日期。基于该列过滤的查询只会读取匹配的分区。避免选择取值过多的列,否则会产生大量细小的分区。
17. 你在分析场景中使用什么文件格式,为什么?
Parquet 这类列式格式将每一列存储在一起,因此只读取少数几列的查询可以跳过其余部分,并且压缩效果好。CSV 或 JSON 这类行式格式易于生成和读取,但在大规模场景下速度慢、体积大。
分布式处理问题
18. Spark 中的 shuffle 是什么,为什么它开销很大?
shuffle 会在机器之间移动数据,使相同 key 的行落到一起,比如在 join 和 group-by 中。它的代价包括网络传输、磁盘写入和排序。要减少它,可以尽早过滤、选择合理的分区数,并在 join 中广播小表,这样大表就不必移动。
19. 如何处理数据倾斜?
倾斜意味着少数几个 key 承载了大部分数据,导致某个任务运行时间远超其他任务。可选方案包括:给热点 key 加随机后缀进行加盐并聚合两次、广播 join 中较小的一侧,以及单独过滤或处理热点 key。
20. Airflow 这样的编排工具做什么?
它按顺序调度和运行任务,定义为有向图,其中每个任务依赖其他任务。它处理重试、回填和告警,并展示哪些运行了、哪些失败了。它负责协调工作。它本身并不做繁重的处理,那应该在数据仓库或处理引擎中运行。
如何准备
- 练习上面的窗口函数模式,直到你能不查资料就写出来。
- 准备一个你构建过的管道,说明数据量、你遇到的故障以及你做了哪些改动。
- 准备好能在白板上画出一个简单的架构,并说明当某个步骤失败时会发生什么。
- 复习你的简历:上面每一个工具都可能被问到。
相关练习,请参阅我们的 Kafka 面试问题、Databricks 面试问题、Snowflake 面试问题 和 系统设计面试问题 指南。
大声练习,用你自己的话来说。事后的文字记录会显示你在哪里啰嗦或跑题了。在任何现场面试或评估中,遵守雇主关于 AI 工具的规定。
用YesToTheOffer练习你的答案
大声排练,根据你自己的简历生成答案,并在之后回顾你的文字记录。30分钟免费,无需订阅。



