两张大表Join跑了2小时,你怎么优化?
本文目录
先说结论
Spark的Join优化按场景分三种:
大表 + 小表: Broadcast Join(小表广播到所有Executor,避免Shuffle)
大表 + 大表: Sort Merge Join(默认,两张表都按Key排序后合并)
大表 + 大表且倾斜: 加盐打散 / Skew Join Hint(处理热点Key)
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
大表Join是Spark性能优化里最经典的场景。很多人的回答停留在“用Broadcast Join”,但面试官会追问:“如果两张都是大表呢?”今天把所有场景的Join优化方案讲清楚。
场景一:Broadcast Join(小表 < 200MB)
小表广播到所有Executor,大表不需要Shuffle。性能提升巨大。
-- Spark SQL自动判断(默认阈值10MB,可以调大)
SET spark.sql.autoBroadcastJoinThreshold = 200m; -- 调到200MB
-- 也可以手动指定
SELECT /*+ BROADCAST(dim_user) */
f.order_id, f.amount, d.user_name
FROM fact_order f
JOIN dim_user d ON f.user_id = d.user_id;
我在出海硬件公司把autoBroadcastJoinThreshold从默认的10MB调到200MB后,大量事实表和维度表的Join自动变成了Broadcast Join,整体作业执行时间减少40%。
场景二:Sort Merge Join(两张都是大表)
当两张表都很大(比如两张各几亿行的事实表),无法广播,Spark默认用Sort Merge Join:
1. Shuffle阶段:两张表都按Join Key重新分区,相同Key的数据去同一个分区
2. Sort阶段:每个分区内按Key排序
3. Merge阶段:如归并排序一样合并两个有序序列
优化手段:增加shuffle.partitions分散数据,确保Join Key上有索引(Parquet的排序列),开启AQE自动调整分区数。
场景三:大表Join且有倾斜(AQE Skew Join)
Spark 3.0+的AQE有自动Skew Join优化:
SET spark.sql.adaptive.enabled = true;
SET spark.sql.adaptive.skewJoin.enabled = true;
SET spark.sql.adaptive.skewJoin.skewedPartitionFactor = 5;
SET spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes = 256m;
-- AQE会自动检测倾斜分区,把大分区拆成多个小任务并行处理
我在出海硬件公司迁移到Databricks后,所有作业默认开启AQE。有一个用户行为表Join广告投放表的作业,之前因为某些头部用户的数据倾斜导致跑3小时,开启AQE后降到45分钟。
面试高频追问:怎么判断Spark用了哪种Join?
-- 查看执行计划
EXPLAIN FORMATTED
SELECT * FROM table_a a JOIN table_b b ON a.id = b.id;
-- 在执行计划里看到:
-- BroadcastHashJoin → Broadcast Join
-- SortMergeJoin → Sort Merge Join
-- ShuffledHashJoin → Shuffle Hash Join(少见)
总结
| Join类型 | 适用场景 | 性能 |
|---|---|---|
| Broadcast Join | 一张表 < 200MB | 最快(无Shuffle) |
| Sort Merge Join | 两张都是大表 | 稳定(默认) |
| AQE Skew Join | 大表+倾斜 | 自动拆分倾斜分区 |
面试时能说清楚三种Join的原理和适用场景,再加一个“把autoBroadcastJoinThreshold调大后性能提升40%”的实战,就很完整。
下一篇聊一个每个数据开发都会遇到的场景:某个Task比其他慢了10倍,这就是数据倾斜。怎么解决?
你们生产环境的Join优化最常用哪种方案?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长