生产上hivesql有哪些优化技巧?

提问者:帅平 问题分类:大数据
生产上hivesql有哪些优化技巧?
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属地:四川省
Missyoulonely
Missyoulonely
写 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属地:四川省
我来回答