Hive在執(zhí)行MapReduce任務(wù)時經(jīng)常會碰到數(shù)據(jù)傾斜的問題涡扼,表現(xiàn)為一個或者幾個reduce節(jié)點運行很慢呻此,延長了整個任務(wù)完成的時間事扭,這是由于某些key的條數(shù)比其他key多很多虏束,這些Key所在的reduce節(jié)點所處理的數(shù)據(jù)量比其他節(jié)點就大很多啤斗,從而導(dǎo)致某幾個節(jié)點遲遲運行不完表箭。
那么經(jīng)常有哪些情況會產(chǎn)生數(shù)據(jù)傾斜呢,又該如何解決钮莲,這里梳理了幾種最常見的數(shù)據(jù)傾斜場景免钻。
一、小表與大表JOIN
小表與大表Join時容易發(fā)生數(shù)據(jù)傾斜臂痕,表現(xiàn)為小表的數(shù)據(jù)量比較少但key卻比較集中伯襟,導(dǎo)致分發(fā)到某一個或幾個reduce上的數(shù)據(jù)比其他reduce多很多,造成數(shù)據(jù)傾斜握童。
優(yōu)化方法:使用Map Join將小表裝入內(nèi)存,在map端完成join操作叛赚,這樣就避免了reduce操作澡绩。有兩種方法可以執(zhí)行Map Join:
(1) 通過hint指定小表做MapJoin
select /*+ MAPJOIN(time_dim) */ count(*) from store_sales join time_dim on ss_sold_time_sk = t_time_sk;
(2) 通過配置參數(shù)自動做MapJoin
核心參數(shù):
參數(shù)名稱 | 默認(rèn)值 | 說明 |
---|---|---|
hive.auto.convert.join | false | 是否將common join(reduce端join)轉(zhuǎn)換成map join |
hive.mapjoin.smalltable.filesize | 25000000 | 判斷為小表的輸入文件大小閾值,默認(rèn)25M |
因此俺附,巧用MapJoin可以有效解決小表關(guān)聯(lián)大表場景下的數(shù)據(jù)傾斜肥卡。
二、大表與大表JOIN
大表與大表Join時事镣,當(dāng)其中一張表的NULL值(或其他值)比較多時步鉴,容易導(dǎo)致這些相同值在reduce階段集中在某一個或幾個reduce上,發(fā)生數(shù)據(jù)傾斜問題璃哟。
優(yōu)化方法:
(1) 將NULL值提取出來最后合并氛琢,這一部分只有map操作;非NULL值的數(shù)據(jù)分散到不同reduce上随闪,不會出現(xiàn)某個reduce任務(wù)數(shù)據(jù)加工時間過長的情況阳似,整體效率提升明顯。這種方法由于有兩次Table Scan會導(dǎo)致map增多铐伴。
SELECT a.user_Id,a. username,b.customer_id
FROM user_info a
LEFT JOIN customer_info b
ON a.user_id = b.user_id
where a.user_id IS NOT NULL
UNION ALL
SELECT a.user_Id,a.username,NULL
FROM user_info a
WHERE a.user_id IS NULL
(2) 在Join時直接把NULL值打散成隨機值來作為reduce的key值撮奏,不會出現(xiàn)某個reduce任務(wù)數(shù)據(jù)加工時間過長的情況,整體效率提升明顯当宴。這種方法解釋計劃只有一次map畜吊,效率一般優(yōu)于第一種方法。
SELECT a.user_id,a.username,b.customer_id
FROM user_info a
LEFT JOIN customer_info b
ON
CASE WHEN
a.user_id IS NULL
THEN
CONCAT ('dp_hive', RAND())
ELSE
a.user_id
END = b.user_id;
三户矢、GROUP BY 操作
Hive做group by查詢玲献,當(dāng)遇到group by字段的某些值特別多的時候,會將相同值拉到同一個reduce任務(wù)進行聚合,也容易發(fā)生數(shù)據(jù)傾斜青自。
優(yōu)化方法:
(1) 開啟Map端聚合
參數(shù)設(shè)置:
參數(shù)名稱 | 默認(rèn)值 | 說明 |
---|---|---|
hive.map.aggr | true(Hive 0.3+) | 是否開啟Map端聚合 |
hive.groupby.mapaggr.checkinterval | 100000 | 在Map端進行聚合操作的條目數(shù)目 |
(2) 有數(shù)據(jù)傾斜時進行負載均衡
參數(shù)設(shè)置:
參數(shù)名稱 | 默認(rèn)值 | 說明 |
---|---|---|
hive.groupby.skewindata | false | 當(dāng)GROUP BY有數(shù)據(jù)傾斜時是否進行負載均衡 |
當(dāng)設(shè)定hive.groupby.skewindata為true時株依,生成的查詢計劃會有兩個MapReduce任務(wù)。在第一個MapReduce 中延窜,map的輸出結(jié)果集合會隨機分布到 reduce 中恋腕, 每個 reduce 做部分聚合操作,這樣處理之后逆瑞,相同的 Group By Key 有可能分發(fā)到不同的 reduce 中荠藤,從而達到負載均衡的目的。在第二個 MapReduce 任務(wù)再根據(jù)第一步中處理的數(shù)據(jù)按照Group By Key分布到reduce中获高,(這一步中相同的key在同一個reduce中)哈肖,最終生成聚合操作結(jié)果。
四念秧、COUNT(DISTINCT) 操作
當(dāng)在數(shù)據(jù)量比較大的情況下淤井,由于COUNT DISTINCT操作是用一個reduce任務(wù)來完成,這一個reduce需要處理的數(shù)據(jù)量太大摊趾,就會導(dǎo)致整個job很難完成币狠,這也可以歸納為一種數(shù)據(jù)傾斜。
優(yōu)化方法:將COUNT DISTINCT使用先GROUP BY再COUNT的方式替換砾层。例如:
select count(id) from (select id from bigtable group by id) a
因此漩绵,count distinct的優(yōu)化本質(zhì)上也是轉(zhuǎn)成group by操作。
往期推薦: