SQL数据倾斜指的是在分布式数据库执行查询任务时,数据没有均匀分配到各个计算节点,导致部分节点需要处理远超其他节点的数据量,进而引发整体查询效率下降的问题。这种问题在大数据量场景下的分组聚合、两表关联等操作中尤为常见。

如何识别SQL数据倾斜
要判断是否存在数据倾斜,首先可以从查询执行表现入手,常见的现象包括:查询进度卡在最后一个或几个任务、部分节点CPU或内存使用率远高于其他节点、相同规模的查询耗时波动极大。更精准的定位需要查看SQL的执行计划,重点关注数据分发阶段的记录。
可以通过数据库提供的执行计划命令查看数据分布情况,以PostgreSQL的分布式扩展Citus为例,查看执行计划的代码如下:
-- 查看SQL执行计划,关注数据分布相关的节点信息
EXPLAIN ANALYZE
SELECT
user_id,
COUNT(order_id) AS order_count
FROM
user_order_table
GROUP BY
user_id;
执行后如果看到某个分片的数据量远大于其他分片,或者某个任务的执行时间占整体时间的90%以上,就可以确定存在数据倾斜问题。
常见的数据倾斜触发原因
- 分区键选择不合理:如果选择的数据分布字段存在大量重复值,比如用性别作为分区键,就会导致数据集中到少数几个分区。
- 关联键数据分布不均:两表关联时,关联字段在一个表中存在大量重复值,比如大表关联小表时,小表的关联键集中在少数几个值上。
- 热点数据集中:某些高频访问的键值数据全部落在同一个节点,比如某个热门商品的ID对应的所有订单数据都存储在同一分区。
- 数据写入时分布不均:写入数据时没有按照分区规则均匀写入,导致部分分区数据量远超设计阈值。
实用的数据分布均衡策略
1. 优化分区键选择
选择分区键时优先选择取值分布均匀、基数高的字段,比如用户ID、订单ID这类唯一性较高的字段,避免使用低基数的枚举字段。如果业务中必须使用低基数字段做分区,可以采用组合分区键的方式,比如把性别和用户ID组合作为分区键,减少数据集中概率。
修改表分区键的示例代码如下,以Citus为例:
-- 重新分布表的分区键,选择user_id作为分布键
SELECT create_distributed_table('user_order_table', 'user_id');
2. 热点数据打散处理
对于存在明显热点的数据,可以在原有键的基础上拼接随机后缀或者哈希值,把热点数据分散到多个分区。比如处理热门商品订单时,可以把商品ID拼接0到9的随机数字作为新的分布键,查询时再对拼接后的键做聚合处理。
热点数据打散的查询示例如下:
-- 对热点商品ID拼接随机后缀,打散数据后再聚合
SELECT
substr(distributed_product_id, 1, length(distributed_product_id)-1) AS product_id,
SUM(sale_amount) AS total_sale
FROM
product_sale_table
WHERE
product_id = 'hot_product_001'
GROUP BY
substr(distributed_product_id, 1, length(distributed_product_id)-1);
3. 调整查询逻辑避免倾斜
对于关联场景的倾斜,可以采用小表广播的方式,把小表的全量数据复制到所有计算节点,避免大表按照关联键分发数据。如果是分组聚合场景的倾斜,可以拆分查询逻辑,先对倾斜的键值单独做处理,再和其他非倾斜数据的结果合并。
小表广播的示例代码如下:
-- 把小表设置为广播表,所有节点都存储全量数据
SELECT create_reference_table('small_dim_table');
4. 参数调优与资源调整
可以通过调整数据库的参数优化倾斜场景下的执行效率,比如增大倾斜节点的内存分配、调整并行任务的数量、设置倾斜检测阈值让数据库自动调整任务分配。部分分布式数据库还支持自适应查询执行,可以在运行时自动感知数据分布并调整执行计划。
不同策略的适用场景对比
| 均衡策略 | 适用场景 | 优缺点 |
|---|---|---|
| 优化分区键 | 新建表或者表数据量不大时 | 从根源解决倾斜,但是需要修改表结构,存量表迁移成本较高 |
| 热点数据打散 | 存在明确热点键的场景 | 无需修改表结构,但是查询逻辑需要额外处理打散后的键 |
| 调整查询逻辑 | 临时查询或者无法修改表结构的场景 | 实施成本低,但是只针对当前查询有效,无法解决根本问题 |
| 参数调优 | 倾斜程度较轻的场景 | 无需修改业务代码,但是对严重倾斜的场景效果有限 |
总结
SQL数据倾斜的解决需要结合具体的业务场景和数据分布特点,优先从数据分布的根源入手选择合理的分区键,对于已经出现的倾斜问题,可以根据场景选择合适的均衡策略。日常开发中建议定期监控数据分布情况和查询执行性能,提前发现潜在的倾斜风险,避免问题影响线上业务。