SQL数据倾斜是执行时因key分布不均导致某task负载过重的现象,常见于GROUP BY和JOIN操作,表现为单个reducer卡死、Shuffle write巨大、GC频繁等;可通过打散倾斜key、加随机前缀、改用Map Join缓解。

什么是 SQL 数据倾斜
数据倾斜不是语法错误,而是执行时的数据分布异常:某一个或几个分组键(GROUP BY 字段)、连接键(JOIN 条件字段)或窗口函数的 PARTITION BY 字段,对应的数据量远超其他值——比如 90% 的订单都属于同一个用户 ID,而其余百万用户只占 10%。
它不会让 SQL 报错,但会让执行计划中某个 task 处理的数据量爆炸式增长,拖慢整个作业。尤其在 Spark SQL、Flink SQL 或 Hive 中,这种现象会直接暴露为「单个 reducer 卡死」「Shuffle write 巨大」「GC 频繁」等现象。
为什么 GROUP BY 和 JOIN 最容易触发倾斜
这两个操作天然依赖 key 的哈希分布。一旦 key 分布不均,哈希后落到同一 partition 的数据就极不均衡:
-
GROUP BY user_id:若存在超级用户(如测试账号、机器人账号),其行为日志占全表 40%,该 group 就会独占一个 reducer 的全部时间 -
LEFT JOIN orders ON users.id = orders.user_id:若users表里有 1 条记录对应 500 万条orders,那么这个 join key 就会引发大量重复计算和内存溢出 - 即使加了
DISTRIBUTE BY或调整spark.sql.adaptive.enabled,也无法绕过底层 key 分布缺陷
简单可落地的缓解手段
不用重写业务逻辑,先试这三招:
前后台订单管理页添加商品缩图显示 后台系统设置可直接对商品缩图大小进行设置 去掉商品图片水印功能 上传一张图片,可同时生成列表页缩图及商品详细页缩图,以不同的大小满足页面不同的需要 商品收藏添加批量删除功能 修改商品详细页会员等级显示BUG 优化缩图生成功能(注:因此次优化已更换上传内核,所以有可能会影响已上传商品图片数据) 加入简繁转换 前台订单管理添加单订单在线支付功能 修正VS081样式前台
- 对倾斜 key 单独打散:比如把
user_id = '0'(已知是脏数据或机器人 ID)提前过滤,或用CASE WHEN把它映射成多个虚拟 ID,再 union 回主结果 - 给 JOIN 加随机前缀:对小表倾斜 key 打上 1–100 的随机数,大表对应 key 也炸开成 100 行,实现“用计算换均衡”——代价是数据量放大,但 shuffle 更稳
- 改用
MAP JOIN(Broadcast Join):当一张表足够小(默认spark.sql.autoBroadcastJoinThreshold=10MB),跳过 shuffle 阶段,自然避开倾斜。注意检查实际广播大小,别因 OOM 反而失败
监控时重点看哪几个指标
光看 SQL 耗时不准确。真正要盯的是执行引擎暴露的底层信号:
- Spark UI 中
Stage页面下各 task 的Duration差异是否超过 10 倍;Shuffle Write Size最大值是不是平均值的 50 倍以上 - Hive 日志里有没有
java.lang.OutOfMemoryError: GC overhead limit exceeded或Failed to allocate memory - Flink Web UI 的
Subtask Metrics中,numRecordsInPerSecond曲线是否出现单点尖峰,且持续时间远长于其他 subtask
这些信号比“SQL 慢”更早、更准。一旦发现,优先查 EXPLAIN 输出里的 Exchange 节点输入行数分布,而不是立刻优化 SQL 写法。










