4 个回答
如果出现数据倾斜的话,表现就是绝大多数数据集中到了某一个或几个 Reduce 节点上,导致任务运行极慢甚至内存溢出。所以这时候需要先找到倾斜的 Key,然后通过给倾斜的 Key 添加随机前缀的方式,将原本一个 Key 的大量数据打散成多个 Key 来处理,最后再对结果进行合并。比如我这里的倾斜的sql:
-- 热门商品item_id=12345有上亿条记录,导致数据倾斜
SELECT
a.user_id,
b.item_name
FROM user_clicks a
JOIN items b ON a.item_id = b.item_id
WHERE a.dt = '2024-01-01';更改后的sql是:-- 对热门商品进行打散处理
SELECT
a.user_id,
b.item_name
FROM user_clicks a
JOIN (
SELECT
item_id,
item_name,
-- 对热门商品添加随机后缀,打散到不同Reduce
CASE
WHEN item_id = '12345' THEN concat(item_id, '_', cast(rand()*10 as int))
ELSE item_id
END as dispersed_id
FROM items
) b ON
CASE
WHEN a.item_id = '12345' THEN concat(a.item_id, '_', cast(rand()*10 as int))
ELSE a.item_id
END = b.dispersed_id
WHERE a.dt = '2024-01-01';发布于:1小时前 IP属地:四川省
查询中重复的子查询会拖慢速度。使用 WITH AS将子查询结果提取成一个临时表,后续可以多次引用。示例如下:
-- 使用WITH AS,子查询只计算一次
WITH user_stats AS (
SELECT
user_id,
COUNT(*) as action_count,
MAX(login_time) as last_login
FROM user_actions
WHERE dt = '2024-01-01'
GROUP BY user_id
)
SELECT
a.user_id,
COALESCE(s.action_count, 0) as action_count, -- 处理NULL值
s.last_login
FROM users a
LEFT JOIN user_stats s ON a.user_id = s.user_id
WHERE a.dt = '2024-01-01';发布于:1小时前 IP属地:四川省
避免直接使用 COUNT(DISTINCT),建议采用先 GROUP BY再 COUNT的两步操作。虽然会多一个 Job,但稳定性更高,更适用于大数据场景。示例:
-- 先GROUP BY再COUNT,虽然多一个Job但更稳定
SELECT COUNT(*) as user_count
FROM (
SELECT user_id
FROM user_logs
WHERE dt = '2024-01-01'
AND user_id IS NOT NULL
GROUP BY user_id -- 先分组去重
) distinct_users;发布于:1小时前 IP属地:四川省
写 JOIN 时要注意条件位置和空值,尽量把副表的过滤条件提前到 ON子句中。同时,如果关联键存在大量 NULL值,容易引发数据倾斜。示例:
-- 正确写法:提前过滤,避免NULL值倾斜
SELECT a.*
FROM user_actions a
LEFT JOIN user_info b ON
a.user_id IS NOT NULL
AND a.user_id = b.user_id
AND b.dt = '2024-01-01' -- 副表条件写在ON里面
WHERE a.dt = '2024-01-01';
-- 如果NULL值也需要保留,可以这样处理倾斜
SELECT a.*
FROM user_actions a
LEFT JOIN user_info b ON
CASE
WHEN a.user_id IS NULL THEN concat('null_', rand()) -- 给NULL加随机后缀
ELSE a.user_id
END = b.user_id
AND b.dt = '2024-01-01'
WHERE a.dt = '2024-01-01';这里需要注意几个点:如果不需要 NULL值,就在 ON条件里加上 a.uid IS NOT NULL。
如果需要保留 NULL值,可以对 NULL键进行随机打散(如使用 concat("test", RAND())),或者先对副表进行去空值的子查询。发布于:1小时前 IP属地:四川省
我来回答
您需要 登录 后回答此问题!
