hive 两个没有null指定的表左关联的结果有null_《数据仓库篇》——Hive的学习笔记3...
《數(shù)據(jù)倉庫篇》——Hive的學(xué)習(xí)筆記1 講了Hive的原理,《數(shù)據(jù)倉庫篇》——Hive的學(xué)習(xí)筆記2 講了Hive的操作,本篇將介紹Hive的優(yōu)化。
本篇將Hive的優(yōu)化分成三個(gè)部分,第一部分是SQL通用語法優(yōu)化,第二部分是針對(duì)Hive所具有的數(shù)據(jù)傾斜的優(yōu)化,第三部分則介紹一些通用性的Hive參數(shù)設(shè)置優(yōu)化。
一、語法優(yōu)化
SQL的語法優(yōu)化本質(zhì)上是如何用更少的計(jì)算資源干相同的活,基于此延伸出幾條原則,這幾條原則又拓展出對(duì)應(yīng)的一些具體方法:
原則1:取更少的數(shù)
這條原則特別樸素,只要數(shù)據(jù)量少了運(yùn)算的效率自然會(huì)提升,但如何能夠取更少地?cái)?shù)的同時(shí)不影響結(jié)果呢?
1、不要用select *
這條不多說了,一些寬表少則二三十,多則上百列,而實(shí)際絕大多數(shù)都是我們不需要的,在select時(shí)只挑選后續(xù)需要用到字段而不是select *,那么運(yùn)算時(shí)間會(huì)成倍減少。
2、謂詞下推
謂詞下推指:
將過濾表達(dá)式盡可能移動(dòng)至靠近數(shù)據(jù)源的位置,以使真正執(zhí)行時(shí)能直接跳過無關(guān)的數(shù)據(jù)。簡單來說就是把where語句盡可能挪到最底層的位置,在最底層就把不需要的數(shù)據(jù)都過濾掉,然后讓真正需要的數(shù)據(jù)參與運(yùn)算,而不是留到最后才進(jìn)行過濾。
根據(jù)謂詞下推的思想,可對(duì)下面的代碼進(jìn)行優(yōu)化:
select優(yōu)化后:
select3、多用子查詢
基于謂詞下推的思想,我們還可以做進(jìn)一步的優(yōu)化,即多用子查詢,上面的代碼可進(jìn)一步優(yōu)化成如下樣子:
select采用子查詢后,盡管會(huì)增加job數(shù)但提前把數(shù)據(jù)完成了過濾,還提高了代碼的可讀性,尤其是當(dāng)需要關(guān)聯(lián)的表和條件成倍增加后,可讀性將會(huì)非常重要。
4、子查詢的去重
當(dāng)子查詢的表中所需的字段存在重復(fù)值,那么對(duì)這些字段提前進(jìn)行去重再進(jìn)行關(guān)聯(lián)同樣會(huì)提高運(yùn)算效率。還是以上面的代碼為例:
select至于為什么用group by而不是distinct去重會(huì)在數(shù)據(jù)傾斜部分進(jìn)行解釋。
5、過濾null值
當(dāng)關(guān)聯(lián)所用到的字段包含了太多null時(shí),需要從業(yè)務(wù)的角度考慮這些為null的數(shù)據(jù)是否有存在的必要,如果不必要的話盡早過濾掉,避免影響關(guān)聯(lián)的效率。
如果確實(shí)需要用到,則可用rand()把數(shù)據(jù)均勻分布在不同的reduce上,避免數(shù)據(jù)傾斜,詳細(xì)可見第二部分,此處僅列出代碼:
select原則2:不排序
SQL中進(jìn)行排序是要消耗計(jì)算資源的,在Hive中這種資源消耗會(huì)更加明顯。子查詢里不要排序這一點(diǎn)就不多說了,子查詢中排序是毫無意義的,同時(shí)在最后的結(jié)果步也盡可能少排序,排序這需求完全可以通過交互查詢的UI或把結(jié)果數(shù)據(jù)導(dǎo)出進(jìn)行替代解決。當(dāng)然,如果進(jìn)行查詢時(shí)沒有UI系統(tǒng),或者不方便把數(shù)據(jù)導(dǎo)出,或者你就是想即時(shí)看到數(shù)據(jù)的排序情況,就當(dāng)這條建議不存在就好,但在子查詢里排序仍然還是毫無意義的。
原則3:分步
該原則主要目的是把大數(shù)據(jù)集拆成小數(shù)據(jù)集來運(yùn)行。
1、減少在selec時(shí)用case when
有時(shí)出結(jié)果時(shí)需要用case when進(jìn)行分類輸出,如下面例子
select但是實(shí)測發(fā)現(xiàn)case when的執(zhí)行效率很低,當(dāng)數(shù)據(jù)量太大的時(shí)候甚至?xí)懿怀鰯?shù),因此上面的代碼可優(yōu)化成如下形式:
select當(dāng)數(shù)據(jù)量很大或者select時(shí)有太多的case when,采用上面的方式其執(zhí)行效率會(huì)提高10倍以上。
2、多用臨時(shí)表
當(dāng)需要建的表其邏輯非常復(fù)雜時(shí),需要考慮用臨時(shí)表的方式把中間邏輯分布執(zhí)行,一來方便閱讀、修改和維護(hù),二來減少硬盤的開銷(相較于建中間表的方式)。
3、where+union all
當(dāng)需要根據(jù)某字段分類匯總時(shí)發(fā)現(xiàn)運(yùn)行速度很慢甚至跑不出結(jié)果,那么有可能是因?yàn)槟骋活愋偷臄?shù)據(jù)樣本量過大造成數(shù)據(jù)傾斜,此時(shí)可考慮通過where過濾+union all合并的方法分步統(tǒng)計(jì)和匯總來處理該問題。
優(yōu)化前:
select優(yōu)化后:
selectSQL語句的優(yōu)化方法貴精不貴多,牢記上述原則和方法在日常取數(shù)建表寫sql時(shí)大部分情況下就已經(jīng)接近最優(yōu)效率了。
二、數(shù)據(jù)傾斜
在展開數(shù)據(jù)傾斜的優(yōu)化之前,需要先了解Hive所采用MapReduce的原理,對(duì)MapReduce原理不熟悉的同學(xué)推薦看
深入淺出講解 MapReduce_嗶哩嗶哩 (゜-゜)つロ 干杯~-bilibili?www.bilibili.com以及
木南:《長安十二時(shí)辰》里的MapReduce原理?zhuanlan.zhihu.com以上圖為例,快速過一遍mapreduce的工作流程:
1、首先把需要處理的數(shù)據(jù)文件上傳到HDFS上,然后這些數(shù)據(jù)會(huì)被分為好多個(gè)小的分片,然后每個(gè)分片對(duì)應(yīng)一個(gè)map任務(wù),推薦情況下分片的大小等于block塊的大小。然后map的計(jì)算結(jié)果會(huì)暫存到一個(gè)內(nèi)存緩沖區(qū)內(nèi),該緩沖區(qū)默認(rèn)為100M,等緩存的數(shù)據(jù)達(dá)到一個(gè)閾值的時(shí)候,默認(rèn)情況下是80%,然后會(huì)在磁盤創(chuàng)建一個(gè)文件,開始向文件里邊寫入數(shù)據(jù)。2、map任務(wù)的輸入數(shù)據(jù)的格式是key-value對(duì)的形式,然后map在往內(nèi)存緩沖區(qū)里寫入數(shù)據(jù)的時(shí)候會(huì)根據(jù)key進(jìn)行排序,同樣溢寫到磁盤的文件里的數(shù)據(jù)也是排好序的,最后map任務(wù)結(jié)束的時(shí)候可能會(huì)產(chǎn)生多個(gè)數(shù)據(jù)文件,然后把這些數(shù)據(jù)文件再根據(jù)歸并排序合并成一個(gè)大的文件。
3、然后每個(gè)分片都會(huì)經(jīng)過map任務(wù)后產(chǎn)生一個(gè)排好序的文件,同樣文件的格式也是key-value對(duì)的形式,然后通過對(duì)key進(jìn)行hash的方式把數(shù)據(jù)分配到不同的reduce里邊去,這樣對(duì)每個(gè)分片的數(shù)據(jù)進(jìn)行hash,再把每個(gè)分片分配過來的數(shù)據(jù)進(jìn)行合并,合并過程中也是不斷進(jìn)行排序的。最后數(shù)據(jù)經(jīng)過reduce任務(wù)的處理就產(chǎn)生了最后的輸出。
簡單來說,map階段負(fù)責(zé)不同節(jié)點(diǎn)上一部分?jǐn)?shù)據(jù)的統(tǒng)計(jì)工作,reduce階段負(fù)責(zé)匯總聚合的工作。
有時(shí)一個(gè)reduce可以處理多個(gè)任務(wù),但一些全局的工作只能讓一個(gè)reduce負(fù)責(zé),例如統(tǒng)計(jì)總行數(shù)、distinct去重等,此時(shí)就reduce就不能有多個(gè)實(shí)例并發(fā)執(zhí)行,這就會(huì)造成其他reduce的任務(wù)已經(jīng)執(zhí)行完了,而負(fù)責(zé)全局的reduce還沒執(zhí)行完,這就是數(shù)據(jù)傾斜的本質(zhì),因此避免數(shù)據(jù)傾斜的核心在于均勻分配任務(wù)。
1、數(shù)據(jù)量大的時(shí)候用group by
當(dāng)需要對(duì)數(shù)據(jù)進(jìn)行去重時(shí),在數(shù)據(jù)量較大的情況下可以選擇用group by而不是distinct,原理如下:
默認(rèn)情況下,map階段同一key數(shù)據(jù)分發(fā)給一個(gè)reduce,當(dāng)一個(gè)key數(shù)據(jù)過大時(shí)就會(huì)發(fā)生數(shù)據(jù)傾斜了。但是并不是所有的聚合操作都只能在reduce完成,很多聚合操作也可以先在map進(jìn)行部分聚合,最后在reduce端得出最終結(jié)果。
開啟Map端聚合參數(shù)設(shè)置
(1)是否在Map端進(jìn)行聚合,默認(rèn)為True
set hive.map.aggr = true;
(2)在Map端進(jìn)行聚合操作的條目數(shù)目
set hive.groupby.mapaggr.checkinterval = 100000;
(3)有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(fù)載均衡(默認(rèn)是false)
set hive.groupby.skewindata = true;
當(dāng)選項(xiàng)設(shè)定為 true,生成的查詢計(jì)劃會(huì)有兩個(gè)MR Job。第一個(gè)MR Job中,Map的輸出結(jié)果會(huì)隨機(jī)分布到Reduce中,每個(gè)Reduce做部分聚合操作,并輸出結(jié)果,這樣處理的結(jié)果是相同的Group By Key有可能被分發(fā)到不同的Reduce中,從而達(dá)到負(fù)載均衡的目的;第二個(gè)MR Job再根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照Group By Key分布到Reduce中(這個(gè)過程可以保證相同的Group By Key被分布到同一個(gè)Reduce中),最后完成最終的聚合操作。
而與之相對(duì)應(yīng)的,distinct則只會(huì)用一個(gè)reduce來執(zhí)行,造成數(shù)據(jù)量過大而讓整體任務(wù)執(zhí)行時(shí)間過長或無法完成。
但是需要注意的是,用group by來去重會(huì)額外增加一個(gè)子查詢,只有當(dāng)數(shù)據(jù)量很大的情況或任務(wù)執(zhí)行中出現(xiàn)嚴(yán)重的數(shù)據(jù)傾斜,group by去重后count才會(huì)比count(distinct)效率更高。
2、Mapjoin
如果不指定MapJoin或者不符合MapJoin的條件,那么Hive解析器會(huì)將Join操作轉(zhuǎn)換成Common Join,即:在Reduce階段完成join。容易發(fā)生數(shù)據(jù)傾斜??梢杂肕apJoin把小表全部加載到內(nèi)存在map端進(jìn)行join,避免reducer處理。
(1)設(shè)置自動(dòng)選擇Mapjoin
set hive.auto.convert.join = true; 默認(rèn)為true
(2)大表小表的閾值設(shè)置(默認(rèn)25M一下認(rèn)為是小表):
set hive.mapjoin.smalltable.filesize=25000000;
數(shù)據(jù)傾斜的處理在hive優(yōu)化中是一個(gè)大課題,實(shí)際場景中所遇到的hive任務(wù)執(zhí)行過長或報(bào)錯(cuò)有80%都與數(shù)據(jù)傾斜有關(guān),后續(xù)有機(jī)會(huì)的話可能專門寫一篇針對(duì)解決數(shù)據(jù)傾斜的文章。
三、參數(shù)優(yōu)化
該部分羅列了一些常用的hive參數(shù)設(shè)置,并逐條做簡單介紹
1、set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveFormat;(默認(rèn)開啟)
將多個(gè)小文件打包作為一個(gè)整體的inputsplit,減少map任務(wù)數(shù)
2、set hive.merge.mapfiles=true;(默認(rèn)值為真)
合并map端小文件的輸出
3、set hive.auto.convert.join=true;
開啟mapjoin
4、set hive.mapjoin.smalltable.filesize=25000000; (默認(rèn)25M)
設(shè)置mapjoin的開啟閾值
5、set hive.optimize.skewjoin=true;
有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(fù)載均衡
6、set hive.skewjoin.key=100000;
表示當(dāng)記錄條數(shù)超過100000時(shí)采用skewjoin操作
7、set hive.exec.parallel=true;
多個(gè)join多個(gè)union all優(yōu)化,開啟不同stage任務(wù)并行計(jì)算
8、set hive.exec.parallel.thread.number=16;(默認(rèn)為8)
同一個(gè)sql允許最大并行度
9、set hive.map.aggr=true;
group by 數(shù)據(jù)傾斜優(yōu)化 設(shè)置在map端進(jìn)行聚合
10、set hive.groupby.skewindata=true;
group by數(shù)據(jù)傾斜優(yōu)化
11、set hive.exec.mode.local.auto=true;
開啟本地模式
12、set mapred.compress.map.output=true;
開啟中間壓縮
以上是hive通用屬性的設(shè)置,下面的參數(shù)主要目的是控制map和reduce的數(shù)量,需要依情況而設(shè)定:
13、set hive.merge.smallfiles.avgsize=16000000;
平均文件大小,是決定是否執(zhí)行合并操作的閾值
14、set mapred.min.split.size.per.node=128000000;
低于128M就算小文件,數(shù)據(jù)在一個(gè)節(jié)點(diǎn)會(huì)合并,在多個(gè)不同的節(jié)點(diǎn)會(huì)把數(shù)據(jù)抓取過來進(jìn)行合并
15、set mapred.min.split.size.per.rack=64000000;
每個(gè)機(jī)架處理的最小split
16、set mapred.max.split.size=256000000;
決定每個(gè)map處理的最大的文件大小
17、set mapred.min.split.size=10000000;
決定每個(gè)map處理的最小的文件大小
18、set hive.merge.size.per.task=256000000;(默認(rèn)值為256000000)
對(duì)map個(gè)數(shù)進(jìn)行設(shè)置
19、set mapred.reduce.tasks=10;
設(shè)置reduce的數(shù)量
20、set hive.exec.reducers.bytes.per.reducer=536870912;(512M)
調(diào)整每個(gè)reduce處理數(shù)據(jù)量的大小
以上關(guān)于map和reduce的參數(shù)需要根據(jù)實(shí)際情況設(shè)置,具體的設(shè)置邏輯礙于篇幅所限就不展開了,如果有機(jī)會(huì)的話需要單獨(dú)列一篇作詳細(xì)介紹。
除了以上的優(yōu)化方向外,還可以通過設(shè)置hive的文件格式來提高效率,目前優(yōu)化做得最好的文件格式就是ORCfile,可以在建表時(shí)通過stored as ORC來調(diào)用。另外,可以根據(jù)實(shí)際工作需要把一些常用的統(tǒng)計(jì)匯總邏輯用中間表的形式存儲(chǔ)起來,便于后續(xù)查詢。
Hive的優(yōu)化是一個(gè)系統(tǒng)性的工作,本篇僅列一二,同時(shí)挖了好幾個(gè)坑(并不),但是由于以后是spark以及其他更優(yōu)秀引擎的天下了,所以如果以后還要對(duì)Hive進(jìn)行優(yōu)化,那大概就是換一個(gè)語言吧(不是)。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的hive 两个没有null指定的表左关联的结果有null_《数据仓库篇》——Hive的学习笔记3...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国航天科工:超低轨卫星星座首发星在研制
- 下一篇: bootstrap 数据加载中提示_解决