奇思妙想的SQL|兼顾性能的数据倾斜处理新姿势

来源:这里教程网 时间:2026-03-01 17:37:41 作者:

来源:阿里云开发者

阿里妹导读

本篇为系列第2篇,分享在支付宝支付数据链路改造升级过程中,针对数据倾斜的优化实践新方法,在解决数据倾斜问题的同时,还能兼顾更优的计算性能!

文章导读

一、场景描述

二、常见的优化方法

2.1.Mapjoin

SELECT /*+MAPJOIN(dim)*/  * FROM (SELECT * FROM dwd_tbl) base LEFT OUTER JOIN (SELECT * FROM dim_tbl) dimON base.dim_key = dim.dim_key

SELECT * FROM (SELECT * FROM dwd_tbl) base LEFT OUTER JOIN (SELECT * FROM dim_tbl) dimON IF(COALESCE(base.dim_key,'')='',CONCAT('HIVE_',RAND()),base.dim_key) = dim.dim_key
此方法适用于被关联表远比主表小,但又因数据大小超过内存容量而无法使用Mapjoin,且主表的数据倾斜程度不大(即极值对应的数据行数相较于值平均对应行数,倍数差距不太大)的情况下可以使用,但整体上此方案只能对数据热点成倍数的削弱一些。

SELECT * FROM (    SELECT *,CAST(RAND()*10 AS BIGINT) AS ext_a    FROM dwd_tbl) base LEFT OUTER JOIN (    SELECT *    FROM dim_tbl    LATERAL VIEW EXPLODE(SPLIT('0;1;2;3;4;5;6;7;8;9',';')) tt AS ext_b    -- 或者Join一个用于倍数膨胀的小表) dimON  base.dim_key = dim.dim_keyAND base.ext_a   = dim.ext_b

2.4.热点数据单独处理/SkewJoin

热点数据单独处理的方案的核心点在于将热点数据提取出来单独处理,热点数据可以用Mapjoin的方式完成关联维表热点记录行,非热点则使用普通的shuffle模式的join方案完成关联。

具体操作主要分三个部分:基于主表统计获得Top热点的属性值;用热点属性值将被关联维表拆成热点小表和非热点表,同时也将主表拆成热点主表和非热点主表;热点小表通过Mapjoin与热点主表join,非热点表与非热点主表join,最终两部分再Union到一起,完成数据关联。

-- Step01:热点数据记录提取
INSERT OVERWRITE TABLE tmp_hot_list PARTITION (dt = '${bizdate}')
SELECT   dim_shop_id AS hot_id
FROM   main_table
WHERE   dt = '${bizdate}'
GROUP BY dim_shop_id
HAVING COUNT(1) > 10000
;

INSERT OVERWRITE TABLE final_result_table PARTITION (dt = '${bizdate}')
-- Step02:热点数据处理,使用MapJoin完成处理
SELECT   /*+MAPJOIN(a2,a3)*/ 
         a1.trade_no    AS trade_no
        ,a1.dim_shop_id AS shop_id
        ,a3.shop_name   AS shop_name
        ,a3.shop_type   AS shop_type
FROM (SELECT * FROM main_table WHERE dt = '${bizdate}') a1 
-- Step02-1:主表用JOIN关联热点表进行热点记录筛选
JOIN (SELECT * FROM tmp_hot_list WHERE dt = '${bizdate}') a2 -- 热点数据清单
ON a1.dim_shop_id = a2.dim_shop_id
-- Step02-2:热点维度数据处理
LEFT OUTER JOIN (
    SELECT /*+MAPJOIN(b2)*/ b1.*
    FROM  (SELECT * FROM dim_table_info WHERE dt = '${bizdate}') b1
    JOIN  (SELECT * FROM tmp_hot_list   WHERE dt = '${bizdate}') b2 -- 热点数据清单
    ON    b1.dim_shop_id = b2.dim_shop_id
) a3
ON    a1.dim_shop_id = a3.dim_shop_id
UNION ALL 
-- Step03:非热点数据处理,使用普通Join完成处理,两张表均需要进行Shuffle
SELECT   /*+MAPJOIN(a12)*/ 
         a11.trade_no    AS trade_no
        ,a11.dim_shop_id AS shop_id
        ,a13.shop_name   AS shop_name
        ,a13.shop_type   AS shop_type
FROM (SELECT * FROM main_table WHERE dt = '${bizdate}') a11 
-- Step03-1:主表用ANTI JOIN关联热点表进行剔除
LEFT ANTI JOIN (SELECT * FROM tmp_hot_list WHERE dt = '${bizdate}') a12
ON a11.dim_shop_id = a12.dim_shop_id
-- Step03-2:非热点维度数据处理
LEFT OUTER JOIN (
    SELECT /*+MAPJOIN(b12)*/ b11.*
    FROM  (SELECT * FROM dim_table_info WHERE dt = '${bizdate}') b11
    LEFT ANTI JOIN  (SELECT * FROM tmp_hot_list WHERE dt = '${bizdate}') b12
    ON    b11.dim_shop_id = b12.dim_shop_id
) a13
ON a11.dim_shop_id = a13.dim_shop_id
;

2.5.方案总结

三、一种新的思路 WithDistmapjoin~

3.1.核心思路

3.2.代码实现

3.3.真实效果

四、方案总结

相关推荐