数据倾斜源头常见于GROUP BY、JOIN和COUNT DISTINCT操作,需通过执行计划与统计信息定位热点key,再以哈希打散、分桶分区、预聚合、引擎参数调优及SQL改写等策略综合治理。

识别倾斜的源头
数据倾斜不是凭空出现的,它总在某个具体操作中暴露出来。最常见的位置是 GROUP BY、JOIN 和 COUNT DISTINCT 这三类操作。比如执行 SELECT user_id, COUNT(*) FROM logs GROUP BY user_id 时,如果少数几个 user_id 占了全表 80% 的记录,那这些 key 就会把一个 Reduce 或 DN 节点压垮。先用 EXPLAIN 或 EXPLAIN PERFORMANCE 查执行计划,再结合统计信息(如直方图)确认字段分布是否严重不均——Oracle 中可查 DBA_TAB_COL_STATISTICS,Hive/Spark 中可用 ANALYZE TABLE 更新后观察。
优化数据分布本身
如果倾斜来自原始数据分布,光调 SQL 很难根治,得从数据组织入手:
- 对热点 key 做哈希打散:比如原 join 字段是
user_id,可改用CONCAT(user_id, '_', FLOOR(RAND() * 100))作为临时关联键,再配合UNION ALL合并结果 - 引入二级分区或分桶:Hive 表可按日期 +
user_id % 64双重分区;DWS 或 StarRocks 中启用分桶列,让数据更均匀落盘 - 预聚合冷热分离:将高频访问的热点用户单独建汇总表,查询时优先走小表,避免每次都在大表上扫全量
适配执行引擎的参数策略
不同引擎有对应的数据倾斜缓解机制,关键是要打开并设合理阈值:
- Hive:开启
hive.groupby.skewindata=true,它会自动触发两阶段聚合;对 join 场景,设hive.skewjoin.key=100000并启用hive.optimize.skewjoin=true - Spark SQL:启用自适应执行(
spark.sql.adaptive.enabled=true),配合spark.sql.adaptive.skewJoin.enabled=true,系统会在运行时自动拆分倾斜 partition - Oracle:确保对倾斜字段收集直方图(
method_opt => 'for columns size auto'),避免优化器误判选择性
写法层面绕过倾斜风险
有些倾斜本质是 SQL 写法放大了问题,稍作调整就能规避:
-
COUNT DISTINCT 改写:先
GROUP BY key去重,再外层COUNT(*),避免单个 task 承载全部 distinct 值 -
大表 join 小表优先用 MapJoin:Hive 加
/*+ MAPJOIN(small_table) */hint;ODPS 设置odps.sql.mapjoin.memory.max=1024 -
过滤条件尽量下推:不要等 JOIN 完再 WHERE,而是
WHERE写在子查询里,提前减少参与 shuffle 的数据量










