2) 由于數(shù)據(jù)類型不一致鳖谈,導(dǎo)致的轉(zhuǎn)換問(wèn)題岁疼,導(dǎo)致的數(shù)據(jù)傾斜
場(chǎng)景說(shuō)明:用戶表中 user_id 字段為 int,log 表中 user_id 為既有 string 也有 int 的類型缆娃。
? ?當(dāng)按照兩個(gè)表的 user_id 進(jìn)行 join 操作的時(shí)候捷绒,默認(rèn)的 hash 操作會(huì)按照 int 類型的 id 進(jìn) 行分配瑰排,這樣就會(huì)導(dǎo)致所有的 string 類型的 id 就被分到同一個(gè) reducer 當(dāng)中。
解決方案:將 INT?類型id , 轉(zhuǎn)換為 STRING 類型的 id.
SELECT *
FROM user AS a
LEFT OUTER JOIN log AS b
ON b.user_id = CAST (a.user_id AS STRING)
;
3) 業(yè)務(wù)數(shù)據(jù)本身分布不均暖侨,導(dǎo)致的數(shù)據(jù)傾斜
i.大表與小表JOIN (Map JOIN)
ii.大表與大表JOIN, 一張表數(shù)據(jù)分布均勻椭住,另一張表數(shù)據(jù)特定的KEY(有限幾個(gè)) 分布不均
iii.大表與大表JOIN, 一張表數(shù)據(jù)分布均勻,另一張表大量的KEY 分布不均
iiii.大表與大表JOIN, 桶表字逗,進(jìn)行表拆分
構(gòu)建數(shù)據(jù)
CREATE TABLE IF NOT EXISTS skew_multi_action_info(
user_id BIGINT
,user_action STRING
);
INSERT INTO TABLE skew_multi_action_info
VALUES
(1, 'cc')
,(1, 'pp')
,(1, 'kk')
,(1, 'kk')
,(1, 'kk')
,(1, 'kk')
,(1, 'kk')
,(1, 'cc')
,(2, 'zz')
,(2, 'zz')
,(2, 'zz')
,(2, 'zS')
,(2, 'zS')
,(2, 'zS')
,(3, 'pp')
,(4, 'lp')
,(5, 'op')
;
CREATE TABLE IF NOT EXISTS skew_user_info_2(
user_id BIGINT
,user_name STRING
);
INSERT INTO TABLE skew_user_info_2
VALUES
(1, 'puzheli')
,(2, 'sjz')
,(3, 'xxx')
,(4, 'ccc')
,(5, 'xdi')
;
i.大表與小表JOIN (Map JOIN)
我們參考Map JOIN 的參數(shù)京郑,去調(diào)整 MAP JOIN 的小表的輸入大小即可。
參考文章 :https://blog.csdn.net/u010003835/article/details/105495067
Map JOIN 會(huì)將小表分發(fā)到JOB 中每個(gè) Map 中葫掉, 相當(dāng)于 map 端執(zhí)行了 JOIN 操作些举,省去了 shuffle 流程,所以避免了大量相同 KEY 傳入到 一個(gè) Reduce 中俭厚。
使用Map JOIN 時(shí)金拒,會(huì)先執(zhí)行一個(gè)本地任務(wù)(mapreduce local task)將小表轉(zhuǎn)成hashtable并序列化為文件再壓縮,隨后這些 hashtable文件會(huì)被上傳到hadoop緩存套腹,提供給各個(gè)mapjoin 使用绪抛。
針對(duì)上面的 數(shù)據(jù),我們?cè)O(shè)置 hive Map JOIN 默認(rèn)優(yōu)化? ??
set hive.auto.convert.join = true;
我們看下執(zhí)行計(jì)劃
STAGE DEPENDENCIES:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? Stage-4 is a root stage? ? ? ? ? ? ? ? ? ? ? ? ?
? Stage-3 depends on stages: Stage-4? ? ? ? ? ? ?
? Stage-0 depends on stages: Stage-3? ? ? ? ? ? ?
STAGE PLANS:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? Stage: Stage-4? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? Map Reduce Local Work? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? Alias -> Map Local Tables:? ? ? ? ? ? ? ? ?
? ? ? ? b? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? Fetch Operator? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? limit: -1? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? Alias -> Map Local Operator Tree:? ? ? ? ? ?
? ? ? ? b? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? TableScan? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? alias: b? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? Statistics: Num rows: 5 Data size: 29 Basic stats: COMPLETE Column stats: NONE
? ? ? ? ? ? HashTable Sink Operator? ? ? ? ? ? ? ?
? ? ? ? ? ? ? keys:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? 0 user_id (type: bigint)? ? ? ? ?
? ? ? ? ? ? ? ? 1 user_id (type: bigint)? ? ? ? ?
? Stage: Stage-3? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? Map Reduce? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? Map Operator Tree:? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? TableScan? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? alias: a? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? Statistics: Num rows: 17 Data size: 68 Basic stats: COMPLETE Column stats: NONE
? ? ? ? ? ? Map Join Operator? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? condition map:? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? Left Outer Join0 to 1? ? ? ? ?
? ? ? ? ? ? ? keys:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? 0 user_id (type: bigint)? ? ? ? ?
? ? ? ? ? ? ? ? 1 user_id (type: bigint)? ? ? ? ?
? ? ? ? ? ? ? outputColumnNames: _col0, _col1, _col6
? ? ? ? ? ? ? Statistics: Num rows: 18 Data size: 74 Basic stats: COMPLETE Column stats: NONE
? ? ? ? ? ? ? Select Operator? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? expressions: _col0 (type: bigint), _col1 (type: string), _col6 (type: string)
? ? ? ? ? ? ? ? outputColumnNames: _col0, _col1, _col2
? ? ? ? ? ? ? ? Statistics: Num rows: 18 Data size: 74 Basic stats: COMPLETE Column stats: NONE
? ? ? ? ? ? ? ? File Output Operator? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? compressed: false? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? Statistics: Num rows: 18 Data size: 74 Basic stats: COMPLETE Column stats: NONE
? ? ? ? ? ? ? ? ? table:? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? input format: org.apache.hadoop.mapred.SequenceFileInputFormat
? ? ? ? ? ? ? ? ? ? ? output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
? ? ? ? ? ? ? ? ? ? ? serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
? ? ? Local Work:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? Map Reduce Local Work? ? ? ? ? ? ? ? ? ? ?
? Stage: Stage-0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? Fetch Operator? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? limit: -1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? Processor Tree:? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ListSink? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
ii.大表與大表JOIN, 一張表數(shù)據(jù)分布均勻电禀,另一張表數(shù)據(jù)特定的KEY(有限幾個(gè)) 分布不均
適用場(chǎng)景:兩個(gè)Hive表進(jìn)行join的時(shí)候幢码,如果數(shù)據(jù)量都比較大,那么此時(shí)可以看一下兩個(gè)Hive表中的key分布情況尖飞。如果出現(xiàn)數(shù)據(jù)傾斜症副,是因?yàn)槠渲心骋粋€(gè)Hive表中的少數(shù)幾個(gè)key的數(shù)據(jù)量過(guò)大,而另一個(gè)Hive表中的所有key都分布比較均勻政基,那么采用這個(gè)解決方案是比較合適的
方案實(shí)現(xiàn)思路:
對(duì)包含少數(shù)幾個(gè)數(shù)據(jù)量過(guò)大的key的那個(gè)表贞铣,通過(guò)sample算子采樣出一份樣本來(lái),然后統(tǒng)計(jì)一下每個(gè)key的數(shù)量沮明,計(jì)算出來(lái)數(shù)據(jù)量最大的是哪幾個(gè)key辕坝。
然后將這幾個(gè)key對(duì)應(yīng)的數(shù)據(jù)從原來(lái)的表中拆分出來(lái),形成一個(gè)單獨(dú)的表荐健,并給每個(gè)key都打上n以內(nèi)的隨機(jī)數(shù)作為前綴酱畅,而不會(huì)導(dǎo)致傾斜的大部分key形成另外一個(gè)表
接著將需要join的另一個(gè)表,也過(guò)濾出來(lái)那幾個(gè)傾斜key對(duì)應(yīng)的數(shù)據(jù)并形成一個(gè)單獨(dú)的表江场,將每條數(shù)據(jù)膨脹成n條數(shù)據(jù)纺酸,這n條數(shù)據(jù)都按順序附加一個(gè)0~n的前綴,不會(huì)導(dǎo)致傾斜的大部分key也形成另外一個(gè)表址否。
再將附加了隨機(jī)前綴的獨(dú)立表與另一個(gè)膨脹n倍的獨(dú)立表進(jìn)行join餐蔬,此時(shí)就可以將原先相同的key打散成n份,分散到多個(gè)task中去進(jìn)行join了。
而另外兩個(gè)普通的表就照常join即可樊诺。
最后將兩次join的結(jié)果使用union算子合并起來(lái)即可仗考,就是最終的join結(jié)果。
數(shù)據(jù)傾斜的SQL
SELECT
a.*
,b.user_name
FROM skew_multi_action_info AS a
JOIN skew_user_info_2 AS b
ON a.user_id = b.user_id
;
針對(duì)上述數(shù)據(jù)樣例:
可以看到??skew_multi_action_info? user_id? IN (1啄骇,2) 大量?jī)A斜,skew_user_info_2 表的數(shù)據(jù)分布 均勻瘟斜。
所以缸夹,我們采用上述方案,拆分并合并的方式
傾斜數(shù)據(jù) 1,2 的結(jié)果
SELECT
tmp_a.uid
,tmp_a.user_action
,tmp_b.user_name
FROM
(
SELECT
CONCAT(a.user_id, '_', CAST ((RAND()*2%2 + 1) AS INT)) AS uid
,a.user_action
FROM skew_multi_action_info AS a
WHERE a.user_id IN (1,2)
) AS tmp_a
JOIN
(
SELECT
CONCAT(user_id,'_1') AS uid
,user_name
FROM skew_user_info_2
WHERE user_id IN (1,2)
UNION ALL
SELECT
CONCAT(user_id,'_2') AS uid
,user_name
FROM skew_user_info_2
WHERE user_id IN (1,2)
) AS tmp_b
ON tmp_a.uid = tmp_b.uid
;
其中膨脹數(shù)據(jù)的部分螺句,我用?-- tmp_b 代替膨脹N倍的操作, 正常應(yīng)該用自定義函數(shù)完成虽惭,即每一行變?yōu)镹行數(shù)據(jù)
(
SELECT?
?CONCAT(user_id,'_1') AS uid
?,user_name
FROM skew_user_info_2?
WHERE user_id IN (1,2)
UNION ALL
SELECT?
?CONCAT(user_id,'_2') AS uid
?,user_name
FROM skew_user_info_2?
WHERE user_id IN (1,2)
) AS tmp_b
整體結(jié)果 :
SELECT
CAST(a.user_id AS STRING) AS uid
,a.user_action
,b.user_name
FROM skew_multi_action_info AS a
JOIN skew_user_info_2 AS b
ON a.user_id = b.user_id
AND a.user_id NOT IN (1,2)
AND b.user_id NOT IN (1,2)
UNION ALL
SELECT
tmp_a.uid
,tmp_a.user_action
,tmp_b.user_name
FROM
(
SELECT
CONCAT(a.user_id, '_', CAST ((RAND()*2%2 + 1) AS INT)) AS uid
,a.user_action
FROM skew_multi_action_info AS a
WHERE a.user_id IN (1,2)
) AS tmp_a
JOIN
(
SELECT
CONCAT(user_id,'_1') AS uid
,user_name
FROM skew_user_info_2
WHERE user_id IN (1,2)
UNION ALL
SELECT
CONCAT(user_id,'_2') AS uid
,user_name
FROM skew_user_info_2
WHERE user_id IN (1,2)
) AS tmp_b
ON tmp_a.uid = tmp_b.uid
;
結(jié)果
+----------+------------------+----------------+
_u1.uid? _u1.user_action? _u1.user_name?
+----------+------------------+----------------+
1_1? ? ? cc? ? ? ? ? ? ? ? puzheli? ? ? ?
1_2? ? ? pp? ? ? ? ? ? ? ? puzheli? ? ? ?
1_2? ? ? kk? ? ? ? ? ? ? ? puzheli? ? ? ?
1_1? ? ? kk? ? ? ? ? ? ? ? puzheli? ? ? ?
1_1? ? ? kk? ? ? ? ? ? ? ? puzheli? ? ? ?
1_2? ? ? kk? ? ? ? ? ? ? ? puzheli? ? ? ?
1_2? ? ? kk? ? ? ? ? ? ? ? puzheli? ? ? ?
1_1? ? ? cc? ? ? ? ? ? ? ? puzheli? ? ? ?
2_1? ? ? zz? ? ? ? ? ? ? ? sjz? ? ? ? ? ?
2_1? ? ? zz? ? ? ? ? ? ? ? sjz? ? ? ? ? ?
2_1? ? ? zz? ? ? ? ? ? ? ? sjz? ? ? ? ? ?
2_1? ? ? zS? ? ? ? ? ? ? ? sjz? ? ? ? ? ?
2_1? ? ? zS? ? ? ? ? ? ? ? sjz? ? ? ? ? ?
2_1? ? ? zS? ? ? ? ? ? ? ? sjz? ? ? ? ? ?
3? ? ? ? pp? ? ? ? ? ? ? ? xxx? ? ? ? ? ?
4? ? ? ? lp? ? ? ? ? ? ? ? ccc? ? ? ? ? ?
5? ? ? ? op? ? ? ? ? ? ? ? xdi? ? ? ? ? ?
+----------+------------------+----------------+
17 rows selected (27.653 seconds)
方案優(yōu)點(diǎn):
? ? 對(duì)于join導(dǎo)致的數(shù)據(jù)傾斜,如果只是某幾個(gè)key導(dǎo)致了傾斜蛇尚,采用該方式可以用最有效的方式打散key進(jìn)行join芽唇。而且只需要針對(duì)少數(shù)傾斜key對(duì)應(yīng)的數(shù)據(jù)進(jìn)行擴(kuò)容n倍,不需要對(duì)全量數(shù)據(jù)進(jìn)行擴(kuò)容取劫。避免了占用過(guò)多內(nèi)存匆笤。
方案缺點(diǎn):如果導(dǎo)致傾斜的key特別多的話,比如成千上萬(wàn)個(gè)key都導(dǎo)致數(shù)據(jù)傾斜谱邪,那么這種方式也不適合炮捧。
iii.大表與大表JOIN, 一張表數(shù)據(jù)分布均勻,另一張表大量的KEY 分布不均
目的 :使用隨機(jī)前綴 和 擴(kuò)容 進(jìn)行 join
適用場(chǎng)景:如果在進(jìn)行join操作時(shí)惦银,表中有大量的key導(dǎo)致數(shù)據(jù)傾斜咆课,那么進(jìn)行分拆key也沒(méi)什么意義,此時(shí)就只能使用最后一種方案來(lái)解決問(wèn)題了扯俱。
方案實(shí)現(xiàn)思路:
該方案的實(shí)現(xiàn)思路基本和“解決方案四”類似书蚪,首先查看Hive表中的數(shù)據(jù)分布情況,找到那個(gè)造成數(shù)據(jù)傾斜的Hive表迅栅,比如有多個(gè)key都對(duì)應(yīng)了超過(guò)1萬(wàn)條數(shù)據(jù)殊校。
然后將該表的每條數(shù)據(jù)都打上一個(gè)n以內(nèi)的隨機(jī)前綴。
同時(shí)對(duì)另外一個(gè)正常的表進(jìn)行擴(kuò)容读存,將每條數(shù)據(jù)都擴(kuò)容成n條數(shù)據(jù)箩艺,擴(kuò)容出來(lái)的每條數(shù)據(jù)都依次打上一個(gè)0~n的前綴。
最后將兩個(gè)處理后的表進(jìn)行join即可宪萄。
方案優(yōu)點(diǎn):對(duì)join類型的數(shù)據(jù)傾斜基本都可以處理艺谆,而且效果也相對(duì)比較顯著,性能提升效果非常不錯(cuò)拜英。
方案缺點(diǎn):
? ? 該方案更多的是緩解數(shù)據(jù)傾斜静汤,而不是徹底避免數(shù)據(jù)傾斜。而且需要對(duì)整個(gè)表進(jìn)行擴(kuò)容,對(duì)內(nèi)存資源要求很高虫给。
iiii.大表與大表JOIN, 桶表藤抡,進(jìn)行表拆分
目的:增加并行度
場(chǎng)景:兩個(gè)大表,數(shù)據(jù)分布均勻抹估,為了提高效率缠黍,使用mapjoin,采用切分大表的方法药蜻,采用將大表切分為小表瓷式,然后進(jìn)行連接
原始測(cè)試表
+----------+------------+
test.id ? test.name ?
+----------+------------+
1 ? ? ? ? aa ? ? ? ?
2 ? ? ? ? bb ? ? ? ?
3 ? ? ? ? cc ? ? ? ?
4 ? ? ? ? dd ? ? ? ?
+----------+------------+
將其切分為兩個(gè):
?select * from test tablesample(bucket 1 out of 2 on id);
+----------+------------+
test.id ? test.name ?
+----------+------------+
2 ? ? ? ? bb ? ? ? ?
4 ? ? ? ? dd ? ? ? ?
+----------+------------+
?select * from test tablesample(bucket 2 out of 2 on id);
+----------+------------+
test.id ? test.name ?
+----------+------------+
1 ? ? ? ? aa ? ? ? ?
3 ? ? ? ? cc ? ? ? ?
+----------+------------+
————————————————
版權(quán)聲明:本文為CSDN博主「高達(dá)一號(hào)」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議语泽,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明贸典。
原文鏈接:https://blog.csdn.net/u010003835/article/details/105495135