Hive的性能優(yōu)化以及數(shù)據(jù)傾斜

hive性能優(yōu)化

一冕茅、Map階段的優(yōu)化:

(控制hive任務(wù)中的map數(shù),確定合適的map數(shù)蛹找,以及每個(gè)map處理合適的數(shù)據(jù)量)姨伤。

map個(gè)數(shù)影響因子:

  1. input目錄中文件總個(gè)數(shù);
  2. input目錄中每個(gè)文件大杏辜病乍楚;
  3. 集群設(shè)置的文件塊大小(默認(rèn)為128M, 可在hive中通過set dfs.block.size;命令查看,不能在hive中自定義修改)届慈;
舉例:
input目錄中有1個(gè)文件(300M)徒溪,會(huì)產(chǎn)生3個(gè)塊(2個(gè)128M,1個(gè)44M)即3個(gè)Map數(shù)金顿。
input目錄中有3個(gè)文件(5M,10M,200M)臊泌,會(huì)產(chǎn)生4個(gè)塊(5M,10M,128M,72M)即4個(gè)Map數(shù)。
適當(dāng)減少M(fèi)ap數(shù):

當(dāng)一個(gè)任務(wù)有很多小文件(遠(yuǎn)遠(yuǎn)小于塊大小128m),會(huì)產(chǎn)生很多Map揍拆,而一個(gè)Map任務(wù)啟動(dòng)和初始化的時(shí)間遠(yuǎn)遠(yuǎn)大于邏輯處理的時(shí)間渠概,就會(huì)造成很大的資源浪費(fèi),而且同時(shí)可執(zhí)行的map數(shù)是受限的嫂拴。

set mapred.max.split.size=100000000;//(100M)
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;//表示執(zhí)行前進(jìn)行小文件合并播揪。
//大于128:按照128M分割;100~128按照100分筒狠;小于100的進(jìn)行合并猪狈。
適當(dāng)增加Map數(shù):

當(dāng)有一個(gè)小于128M的文件(其中有上千萬的數(shù)據(jù),字段少并且數(shù)據(jù)單位小)窟蓝,如果map處理的邏輯比較復(fù)雜罪裹,用一個(gè)map任務(wù)去做饱普,耗時(shí)比較大。

set mapred.reduce.tasks=10;
create table a_1 as 
select * from a distribute by rand();
//表示通過設(shè)置Map任務(wù)數(shù)來中加Map状共,把a(bǔ)表中的數(shù)據(jù)均勻的放到a_1目錄下10個(gè)文件中套耕。
Map端聚合:
set  hive.map.aggr=true ;(默認(rèn)為true)

二、Reduce階段的優(yōu)化:

2.1 指定reduce數(shù)量
 set mapred.reduce.tasks=10
2.2未指定reduce數(shù)量
param1:hive.exec.reducers.bytes.per.reducer(默認(rèn)為1000^3)
param2:hive.exec.reducers.max(默認(rèn)為999)
reduceNum = min(param2峡继,總輸入數(shù)據(jù)量/param1(reduceNum = InputFileSize / bytes per reducer))

通常情況下冯袍,有必要手動(dòng)指定reducer個(gè)數(shù)∧肱疲考慮到map階段的輸出數(shù)據(jù)量通常會(huì)比輸入有大幅減少康愤,因此即使不設(shè)定reducer個(gè)數(shù),重設(shè)參數(shù)2還是必要的舶吗。依據(jù)Hadoop的經(jīng)驗(yàn),可以將參數(shù)2設(shè)定為0.95*(集群中TaskTracker個(gè)數(shù))誓琼。

三检激、其他優(yōu)化:

Multi-insert & multi-group by

從一份基礎(chǔ)表中按照不同的維度,一次組合出不同的數(shù)據(jù)

FROM from_statement
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1)] select_statement1 group by key1
INSERT OVERWRITE TABLE tablename2 [PARTITION(partcol2=val2 )] select_statement2 group by key2
#具體實(shí)例
FROM pv_users 
INSERT OVERWRITE TABLE pv_gender_sum
SELECT pv_users.gender, count(DISTINCT pv_users.userid) 
GROUP BY pv_users.gender 
INSERT OVERWRITE DIRECTORY '/opt/data/users/pv_age_sum'
SELECT pv_users.age, count(DISTINCT pv_users.userid) 
GROUP BY pv_users.age; 
生成MR Job 個(gè)數(shù)
生成一個(gè)MR Job

多表連接腹侣,如果多個(gè)表中每個(gè)表都使用同一個(gè)列進(jìn)行連接(出現(xiàn)在JOIN子句中)恶迈,則只會(huì)生成一個(gè)MR Job呻右。

SELECT a.val, b.val, c.val FROM a 
JOIN b ON (a.key = b.key1) 
JOIN c ON (c.key = b.key1)

三個(gè)表a客扎、b胧瓜、c都分別使用了同一個(gè)字段進(jìn)行連接,亦即同一個(gè)字段同時(shí)出現(xiàn)在兩個(gè)JOIN子句中跺株,從而只生成一個(gè)MR Job复濒。

生成多個(gè)MR Job

多表連接,如果多表中帖鸦,其中存在一個(gè)表使用了至少2個(gè)字段進(jìn)行連接(同一個(gè)表的至少2個(gè)列出現(xiàn)在JOIN子句中)芝薇,則會(huì)至少生成2個(gè)MR Job。

SELECT a.val, b.val, c.val FROM a 
JOIN b ON (a.key = b.key1) 
JOIN c ON (c.key = b.key2)

三個(gè)表基于2個(gè)字段進(jìn)行連接作儿,這兩個(gè)字段b.key1和b.key2同時(shí)出現(xiàn)在b表中洛二。連接的過程是這樣的:首先a和b表基于a.key和b.key1進(jìn)行連接,對(duì)應(yīng)著第一個(gè)MR Job攻锰;表a和b連接的結(jié)果晾嘶,再和c進(jìn)行連接,對(duì)應(yīng)著第二個(gè)MR Job娶吞。

數(shù)據(jù)傾斜:

傾斜原因:

map輸出數(shù)據(jù)按key Hash的分配到reduce中垒迂,由于key分布不均勻業(yè)務(wù)數(shù)據(jù)本身的特性妒蛇、建表時(shí)考慮不周机断、某些SQL語句本身就有數(shù)據(jù)傾斜等原因造成的reduce上的數(shù)據(jù)量差異過大楷拳,所以如何將數(shù)據(jù)均勻的分配到各個(gè)reduce中,就是解決數(shù)據(jù)傾斜的根本所在吏奸。

解決方案:

1. 空值數(shù)據(jù)傾斜

join的key值發(fā)生傾斜欢揖,key值包含很多空值或是異常值,這種情況可以對(duì)異常值賦一個(gè)隨機(jī)值來分散key奋蔚。
案例:在日志中她混,常會(huì)有信息丟失的問題,比如日志中的 user_id泊碑,如果取其中的 user_id 和 用戶表中的user_id 關(guān)聯(lián)坤按,會(huì)碰到數(shù)據(jù)傾斜的問題。

select * from log l
left outer join user u on 
case when (l.user_id is null or I.user_id='-' or I.user_id='0') 
then concat(‘sql_hive’,rand() ) else l.user_id end = u.user_id;
2. Join操作產(chǎn)生數(shù)據(jù)傾斜
2.1 大表和小表Join

產(chǎn)生原因:Hive在進(jìn)行join時(shí)馒过,按照join的key進(jìn)行分發(fā)臭脓,而在join左邊的表的數(shù)據(jù)會(huì)首先讀入內(nèi)存,如果左邊表的key相對(duì)分散沉桌,讀入內(nèi)存的數(shù)據(jù)會(huì)比較小谢鹊,join任務(wù)執(zhí)行會(huì)比較快;而如果左邊的表key比較集中留凭,而這張表的數(shù)據(jù)量很大,那么數(shù)據(jù)傾斜就會(huì)比較嚴(yán)重偎巢,而如果這張表是小表蔼夜,則還是應(yīng)該把這張表放在join左邊。
解決方式:使用map join讓小的維度表先進(jìn)內(nèi)存压昼。在map端完成reduce求冷。
在0.7.0版本之前:需要在sql中使用 /*+ MAPJOIN(smallTable) */ ;

SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a
JOIN b ON a.key = b.key;

在0.7.0版本之后:可以配置hive.auto.convert.join窍霞。

配置項(xiàng) 缺省值 配置說明
hive.auto.convert.join (0.7.0-0.10.0)false; (0.11.0-)true 注意:hive-default.xml模板中錯(cuò)誤地將默認(rèn)設(shè)置為false匠题,在Hive 0.11.0到0.13.1
hive.smalltable.filesize(0.7.0) or hive.mapjoin.smalltable.filesize(0.8.1) 25000000 默認(rèn)值為2500000(25M),通過配置該屬性來確定使用該優(yōu)化的表的大小,如果表的大小小于此值就會(huì)被加載進(jìn)內(nèi)存中

注意:使用默認(rèn)啟動(dòng)該優(yōu)化的方式如果出現(xiàn)默名奇妙的BUG(比如MAPJOIN并不起作用),就將以下兩個(gè)屬性置為fase手動(dòng)使用MAPJOIN標(biāo)記來啟動(dòng)該優(yōu)化

hive.auto.convert.join=false(關(guān)閉自動(dòng)MAPJOIN轉(zhuǎn)換操作)
hive.ignore.mapjoin.hint=false(不忽略MAPJOIN標(biāo)記)

對(duì)于以下查詢是不支持使用方法二(MAPJOIN標(biāo)記)來啟動(dòng)該優(yōu)化的

select /*+MAPJOIN(smallTableTwo)*/ idOne, idTwo, value FROM
  ( select /*+MAPJOIN(smallTableOne)*/ idOne, idTwo, value FROM
    bigTable JOIN smallTableOne on (bigTable.idOne = smallTableOne.idOne)                                                  
  ) firstjoin                                                            
  JOIN                                                                 
  smallTableTwo ON (firstjoin.idTwo = smallTableTwo.idTwo)  

但是但金,如果使用的是方法一即沒有MAPJOIN標(biāo)記則以上查詢語句將會(huì)被作為兩個(gè)MJ執(zhí)行韭山,進(jìn)一步的,如果預(yù)先知道表大小是能夠被加載進(jìn)內(nèi)存的冷溃,則可以通過以下屬性來將兩個(gè)MJ合并成一個(gè)MJ

hive.auto.convert.join.noconditionaltask:Hive在基于輸入文件大小的前提下將普通JOIN轉(zhuǎn)換成MapJoin钱磅,
并是否將多個(gè)MJ合并成一個(gè)
hive.auto.convert.join.noconditionaltask.size:
多個(gè)MJ合并成一個(gè)MJ時(shí),其表的總的大小須小于該值似枕,同時(shí)hive.auto.convert.join.noconditionaltask必須為true
2.2 大表和大表Join

產(chǎn)生原因:業(yè)務(wù)數(shù)據(jù)本身的特性盖淡,導(dǎo)致兩個(gè)表都是大表。
解決方式:業(yè)務(wù)削減凿歼。
案例:user 表有 500w+ 的記錄褪迟,把 user 分發(fā)到所有的 map 上也是個(gè)不小的開銷冗恨,而且 map join 不支持這么大的小表。如果用普通的 join味赃,又會(huì)碰到數(shù)據(jù)傾斜的問題派近。

select * from log l left outer join user u
 on l.user_id = u.user_id;

解決方法:當(dāng)天登陸的用戶其實(shí)很少,先只查詢當(dāng)天登錄的用戶,log里user_id有上百萬個(gè)洁桌,這就又回到原來map join問題渴丸。所幸,每日的會(huì)員uv不會(huì)太多另凌,有交易的會(huì)員不會(huì)太多谱轨,有點(diǎn)擊的會(huì)員不會(huì)太多,有傭金的會(huì)員不會(huì)太多等等吠谢。所以這個(gè)方法能解決很多場(chǎng)景下的數(shù)據(jù)傾斜問題土童。

select /*+mapjoin(u2)*/* from log l2
left outer join
 (
select  /*+mapjoin(l1)*/u1.*
from ( select distinct user_id from log ) l1
join user u1 on l1.user_id = u1.user_id
) u2
on l2.user_id = u2.user_id;
3. count distinct 聚 合 時(shí) 存 在 大 量 特 殊 值

產(chǎn)生原因: 做count distinct時(shí),該字段存在大量值為NULL或空的記錄工坊。
解決方式: 做count distinct時(shí)献汗,將值為空的情況單獨(dú)處理,如果是計(jì)算count distinct王污,可以不用處理罢吃,直接過濾,在最后結(jié)果中加1昭齐。如果還有其他計(jì)算尿招,需要進(jìn)行g(shù)roup by,可以先將值為空的記錄單獨(dú)處理阱驾,再和其他計(jì)算結(jié)果進(jìn)行union就谜。
案例
1.只計(jì)算count distinct

select cast(count(distinct user_id)+1 as bigint) as user_cnt
from user
where user_id is not null and user_id <> '';

2.計(jì)算完count distinct 后面還有 group by。同一個(gè)reduce上進(jìn)行distinct操作時(shí)壓力很大,先將值為空的記錄單獨(dú)處理里覆,再和其他計(jì)算結(jié)果進(jìn)行union丧荐。
在Hive中,經(jīng)常遇到count(distinct)操作喧枷,這樣會(huì)導(dǎo)致最終只有一個(gè)reduce虹统,我們可以先group 再在外面包一層count,就可以了割去。

select day,
count(case when type='session' then 1 else null end) as session_cnt,
count(case when type='user' then 1 else null end) as user_cnt
from (
  select day,type
  from (
    select day,session_id,'session' as type from log
    union all
    select day user_id,'user' as type from log
  )
  group by day,type
)t1 
group by day;
4. group by 產(chǎn)生傾斜的問題
set hive.map.aggr=true

開啟map端combiner:在Map端做combine,若map各條數(shù)據(jù)基本上不一樣, 聚合無意義窟却,通過如下參數(shù)設(shè)置。

hive.groupby.mapaggr.checkinterval = 100000 (默認(rèn))
hive.map.aggr.hash.min.reduction=0.5(默認(rèn))

解釋:預(yù)先取100000條數(shù)據(jù)聚合,如果聚合后的條數(shù)小于100000*0.5呻逆,則不再聚合夸赫。

set hive.groupby.skewindata=true;//決定  group by 操作是否支持傾斜數(shù)據(jù)咖城。

注意:只能對(duì)單個(gè)字段聚合茬腿。
控制生成兩個(gè)MR Job,第一個(gè)MR Job Map的輸出結(jié)果隨機(jī)分配到reduce中減少某些key值條數(shù)過多某些key條數(shù)過小造成的數(shù)據(jù)傾斜問題呼奢。
在第一個(gè) MapReduce 中,map 的輸出結(jié)果集合會(huì)隨機(jī)分布到 reduce 中切平, 每個(gè)reduce 做部分聚合操作握础,并輸出結(jié)果。這樣處理的結(jié)果是悴品,相同的 Group By Key 有可能分發(fā)到不同的reduce中禀综,從而達(dá)到負(fù)載均衡的目的;
第二個(gè) MapReduce 任務(wù)再根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照 Group By Key 分布到 reduce 中(這個(gè)過程可以保證相同的 Group By Key 分布到同一個(gè) reduce 中)苔严,最后完成最終的聚合操作定枷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市届氢,隨后出現(xiàn)的幾起案子欠窒,更是在濱河造成了極大的恐慌,老刑警劉巖退子,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岖妄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡寂祥,警方通過查閱死者的電腦和手機(jī)荐虐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壤靶,“玉大人缚俏,你說我怎么就攤上這事≈椋” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵恬惯,是天一觀的道長向拆。 經(jīng)常有香客問我,道長酪耳,這世上最難降的妖魔是什么浓恳? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮碗暗,結(jié)果婚禮上颈将,老公的妹妹穿的比我還像新娘。我一直安慰自己言疗,他們只是感情好晴圾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著噪奄,像睡著了一般死姚。 火紅的嫁衣襯著肌膚如雪人乓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天都毒,我揣著相機(jī)與錄音色罚,去河邊找鬼。 笑死账劲,一個(gè)胖子當(dāng)著我的面吹牛戳护,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瀑焦,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼腌且,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蝠猬?” 一聲冷哼從身側(cè)響起切蟋,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎榆芦,沒想到半個(gè)月后柄粹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匆绣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年驻右,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崎淳。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡堪夭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拣凹,到底是詐尸還是另有隱情森爽,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布嚣镜,位于F島的核電站爬迟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏菊匿。R本人自食惡果不足惜付呕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跌捆。 院中可真熱鬧徽职,春花似錦、人聲如沸佩厚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至育韩,卻和暖如春克蚂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筋讨。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工埃叭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人悉罕。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓赤屋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親壁袄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子类早,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354