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