订阅更新

查询突然变慢了,怎么快速定位问题?——执行计划分析和性能排查

数据湖手册 第 14 题 约 8 分钟读完

本文目录
  1. 先说结论
  2. 真实案例:查询从1分钟变成10分钟
  3. 执行计划分析怎么看
  4. Spark UI怎么看
  5. 常见性能问题和解决方案
  6. 面试高频追问
  7. 实战踩坑:谓词下推失效导致查询超时
  8. 总结

先说结论

排查思路:先看执行计划EXPLAIN,确认是否走了索引分区剪枝;再看Spark UI找到慢的阶段Stage;最后看慢的任务Task定位具体原因.

关键指标:Shuffle Read Write数据量、Task执行时间、GC时间、Spark UI的SQL标签页查看执行计划.

常见原因:数据倾斜某个Task特别慢、小文件太多Driver收集文件慢、谓词下推失效扫描过多数据、Join策略错误.

最佳实践:定期收集统计信息ANALYZE TABLE、监控慢查询、设置合理的并行度、启用AQE自适应查询.

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

这道题面试官问得很多,因为查询突然变慢是生产环境最常见的问题之一。我在某出海硬件品牌遇到过昨天还跑1分钟的查询今天花了10分钟的问题。很多人只知道看Spark UI,但说不清楚怎么看执行计划。面试官想听的是你能说清楚排查思路和实战经验.

真实案例:查询从1分钟变成10分钟

2023年在某知名出海硬件品牌,我们的用户行为分析查询突然变慢了.

SELECT user_id, event_type, COUNT(*) as event_count
FROM user_behavior
WHERE dt = '2024-03-19'
GROUP BY user_id, event_type;

这个查询平时运行时间约1分钟,但某天突然花了10分钟.

排查步骤1:查看执行计划用EXPLAIN查看执行计划.

排查步骤2:查看Spark UI打开Spark UI查看Stages页面,发现Stage 2 Aggregate阶段花了9分30秒,有200个Task,其中199个Task花了10秒,但有1个Task花了9分钟.

定位问题:这是典型的数据倾斜问题。某个user_id的数据量特别大,导致那个Task特别慢.

# Spark UI显示的Task执行时间
Stage 2 (Aggregate):
  Task 1:   Duration: 10 seconds  (100万行)
  Task 2:   Duration: 10 seconds  (100万行)
  ...
  Task 199: Duration: 10 seconds  (100万行)
  Task 200: Duration: 540 seconds (5000万行!)  <- 这个Task特别慢

解决方案:过滤掉爬虫数据,增加shuffle分区数从200加到400。改后查询时间从10分钟降到1分钟.

// 解决方案:增加shuffle分区数
spark.conf.set("spark.sql.shuffle.partitions", "400")  // 从200加到400
 
// 过滤爬虫数据
val result = spark.sql("""
  SELECT user_id, event_type, COUNT(*)
  FROM user_behavior
  WHERE dt = '2024-03-19'
    AND user_agent NOT LIKE '%bot%'
  GROUP BY user_id, event_type
""")

执行计划分析怎么看

执行计划Execution Plan是Spark SQL的执行蓝图。通过df.explain或Spark UI的SQL标签页可以查看.

// 查看执行计划的三种方式
val df = spark.sql("SELECT * FROM user_behavior WHERE dt='2024-03-19'")
 
// 1) 简单执行计划
df.explain()
 
// 2) 详细执行计划(推荐)
df.explain(extended = true)
 
// 3) Spark UI的SQL标签页(可视化)

执行计划的关键部分:1)Scan数据源扫描:看是否有PartitionFilters分区剪枝和PushedFilters谓词下推;2)Exchange Shuffle:看Shuffle方式;3)Aggregate聚合:看是否部分聚合.

// 执行计划示例(标注关键部分)
== Physical Plan =
* Project ...           -- 投影(选择列)
* HashAggregate ...       -- 聚合(GROUP BY)
+- Exchange ...              -- Shuffle(数据交换)
   +- * HashAggregate ... -- 部分聚合
      +- * Filter ...           -- 过滤(WHERE)
         +- * Scan ...          -- 扫描表
 
// 关键指标:
// 1) Scan后面的PartitionFilters:分区剪枝
// 2) Filter后面的PushedFilters:谓词下推
// 3) Exchange后面的数量:Shuffle分区数

Spark UI怎么看

Jobs页面:查看作业的整体进度。可以看到每个Job的Status和Duration。如果某个Job特别慢,点击进入查看详情.

Stages页面:查看每个Stage的执行情况。关键指标:如果某个Stage的Duration特别长,或者Task执行时间差异很大数据倾斜,就是问题所在.

Storage页面:查看缓存的表。可以看到哪些表被缓存了、缓存的大小.

SQL标签页:查看SQL的执行计划可视化。比df.explain更直观,可以看到每个操作的数据量、耗时.

Executors页面:查看Executor的状态。可以看到每个Executor的内存使用、GC时间、磁盘使用。如果GC时间特别高(大于10%),说明内存不够.

常见性能问题和解决方案

问题症状原因解决方案
数据倾斜某个Task特别慢某个key的数据量特别大加盐、增加分区数、过滤倾斜数据
小文件太多Driver收集文件慢每个分区只有几MBOPTIMIZE合并小文件
谓词下推失效Scan阶段慢使用UDF或子查询改写SQL、避免UDF
Join策略错误Exchange慢大表Join没用Broadcast调整autoBroadcastJoinThreshold
内存不足GC时间长OOM数据量超过内存增加Executor内存

面试高频追问

追问一:如何快速定位数据倾斜?

看Spark UI的Stages页面,找到Duration最长的Stage,点击进去查看Task列表。如果某个Task的Duration是其他Task的10倍以上,且Input Output数据量也大很多,就是数据倾斜.

追问二:谓词下推失效了怎么排查?

用df.explain查看执行计划,看Filter操作后面是否有PushedFilters。如果没有,说明谓词下推失效。常见原因:使用UDF、过滤条件包含子查询、统计信息过期.

追问三:Shuffle Read Write数据量多少算过大?

如果Shuffle数据量大于表总大小的50%,说明Shuffle了很多数据,可能需要优化Join方式用Broadcast Join。如果某个Stage的Shuffle特别大其他Stage的10倍,说明有数据倾斜.

实战踩坑:谓词下推失效导致查询超时

2023年在某出海硬件品牌,我们遇到过谓词下推失效导致查询超时的问题。age列是通过UDF计算的.

// 问题代码:age列通过UDF计算
spark.udf.register("calcAge", (birthday: String) => ...)
val df = spark.sql("SELECT *, calcAge(birthday) as age FROM user_behavior")
 
// 执行计划显示:
// * Filter (age > 25)  -- 没有PushedFilters!
//   +- Scan user_behavior  -- 谓词下推失效

排查发现:因为age列是通过UDF计算的,谓词下推无法生效,Spark需要在读取所有数据后才能过滤age大于25的数据.

解决方案:我们做了两件事:1)将age列存储到user_behavior表(而不是通过UDF计算);2)收集统计信息ANALYZE TABLE。改后查询时间从超时降到1分钟.

-- 改进方案:将age列存储到表中
-- 1)修改ETL,将age列写入user_behavior
INSERT INTO user_behavior
SELECT ub.*, u.age
FROM user_behavior_staging ub
JOIN users u ON ub.user_id = u.user_id;
 
-- 2)收集统计信息
ANALYZE TABLE user_behavior COMPUTE STATISTICS FOR COLUMNS age;

改进效果:改后谓词下推生效,查询性能大幅提升.

总结

查询突然变慢的排查思路是:先看执行计划EXPLAIN,确认分区剪枝和谓词下推是否生效;再看Spark UI找到慢的阶段Stage和慢的任务Task;最后定位具体原因。关键指标是:Shuffle Read Write数据量、Task执行时间、GC时间。最佳实践是:定期收集统计信息、监控慢查询、设置合理的并行度。面试时能说清楚排查思路、执行计划怎么看、常见问题及解决方案,就很稳.

下一篇聊一个很多人问的问题:Delta Lake、Iceberg、Hudi怎么选?——三大数据湖格式对比和选型指南

你们生产环境遇到过查询突然变慢的问题吗?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器