🎁 立即注册,最多可免费使用 30 分钟在线 AI,无需信用卡。

数据工程师面试问题与答案(2026):SQL、管道和Spark

October 9, 2026
20个数据工程师面试问题及答案:带有测试示例的SQL窗口函数、ETL与ELT、幂等管道、数据质量、建模、Spark shuffle和Airflow。
数据工程师面试问题与答案(2026):SQL、管道和Spark
数据工程师面试问题
数据工程面试
SQL窗口函数面试
ETL与ELT
Spark面试问题

数据工程师面试考察三件事: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. 如何优化慢查询?

  1. 在改动任何东西之前先看查询计划。
  2. 检查过滤条件能否用上索引,以及列上的函数是否阻止了索引使用。
  3. 减少扫描的数据量:只选需要的列,尽早过滤,对大表按日期分区。
  4. 用连接或公共表表达式替换重复的子查询,并检查连接中是否意外产生了行数膨胀。
  5. 对于数据仓库,检查聚簇键或排序键,以及每个查询读取了多少数据。

管道设计问题

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 这样的编排工具做什么?

它按顺序调度和运行任务,定义为有向图,其中每个任务依赖其他任务。它处理重试、回填和告警,并展示哪些运行了、哪些失败了。它负责协调工作。它本身并不做繁重的处理,那应该在数据仓库或处理引擎中运行。

如何准备

  1. 练习上面的窗口函数模式,直到你能不查资料就写出来。
  2. 准备一个你构建过的管道,说明数据量、你遇到的故障以及你做了哪些改动。
  3. 准备好能在白板上画出一个简单的架构,并说明当某个步骤失败时会发生什么。
  4. 复习你的简历:上面每一个工具都可能被问到。

相关练习,请参阅我们的 Kafka 面试问题、Databricks 面试问题、Snowflake 面试问题 和 系统设计面试问题 指南。

大声练习,用你自己的话来说。事后的文字记录会显示你在哪里啰嗦或跑题了。在任何现场面试或评估中,遵守雇主关于 AI 工具的规定。

用YesToTheOffer练习你的答案

大声排练,根据你自己的简历生成答案,并在之后回顾你的文字记录。30分钟免费,无需订阅。

iOS & Android — 即将推出
查看价格