数据倾斜

数据倾斜是在做计算的时候数据分配不均匀导致,数据分配不均有可能发生在:
1.join列
问题根源:
SELECT COUNT(*) FROM orders o JOIN customer c ON o.customer_number = c.customer_number;
比如某个customer有一千多万订单,如果按照customer_number进行hash分布计算的时候,就会发生数据倾斜现像

解决方案
-- 优化前(倾斜,慢)
SELECT COUNT() FROM orders o JOIN customer c ON o.customer_number = c.customer_number;
-- 优化后(用 Broadcast Join,快)
SELECT COUNT(
) FROM orders o JOIN [broadcast] customer c ON o.customer_number = c.customer_number;
小表(customer)被 “广播” 到所有 BE 节点(每个节点都有一份小表数据);

2.过滤列
问题根源:
select count(*) from orders, customer where o_custkey = c_custkey and o_orderdate < '1920-01-02';

  1. 优化器的「预期估算」(基于统计信息)
    优化器通过表的统计信息(如列基数、过滤条件选择率)估算:
    过滤条件 A.order_date < '2025-01-01' 会筛选掉 90% 数据,估算 A 过滤后行数为 100 万行(小表);
    B 表无过滤条件,估算行数仍为 1000 万行(大表);
    因此优化器选择 Join 顺序:A(估算小表)→ B(估算大表)(驱动表:A,被驱动表:B)。
  2. 实际数据分布(因倾斜导致估算偏差)
    由于数据倾斜(如 2025-01-01 前的订单集中在少数客户,且该部分客户的订单数据未被统计信息捕捉),实际过滤后:
    A 表实际行数为 5000 万行(因倾斜数据未被有效筛选,实际为大表);
    B 表实际行数仍为 1000 万行(实际为小表);
    此时优化器选择的 A→B 顺序,变成「大表驱动小表」,与最优原则完全相反。

解决方案:
-- 优化前(优化器选错顺序)
select count() from orders, customer where o_custkey = c_custkey and o_orderdate < '1920-01-02';
-- 优化后(强制 orders 先 Join customer,快)
select /
+ leading(customer orders) / count()
from orders, customer
where o_custkey = c_custkey and o_orderdate < '1920-01-02';

3.groupby 列
问题根源:
Group By 列(device_id)存在明显倾斜 —— 少数 device_id(如某几台测试车辆)对应的数据量占比极高(如单个 device_id 对应 30% 数据,其余 device_id 仅占千分之几);
默认按「Group By 列 Hash 分桶」,即将相同 device_id 的数据分发到同一个 BE 节点,由该节点完成聚合计算

解决方案:通过 DISTRIBUTE_BY_RAND() Hint 覆盖默认的「Hash 分桶」,改为「随机分桶」—— 将原本集中在单个节点的倾斜分组数据,随机分发到所有 BE 节点,再通过「局部聚合 + 全局聚合」两步完成计算

-- 优化前(默认 Hash 分桶,倾斜慢,可能 OOM)
SELECT
device_id,
SUM(sensor_value) AS total_value,
COUNT(*) AS data_count
FROM sensor_data
WHERE dt = '2025-01-01'
GROUP BY device_id;

-- 优化后(随机分桶打散,无倾斜,高效)
SELECT /*+ DISTRIBUTE_BY_RAND() / -- 强制随机分桶分发数据
device_id,
SUM(sensor_value) AS total_value,
COUNT(
) AS data_count
FROM sensor_data
WHERE dt = '2025-01-01'
GROUP BY device_id;

posted @ 2025-12-08 15:59  秋水依然  阅读(7)  评论(0)    收藏  举报