基本介紹
- 書名:Java私塾:hive 最佳化——深入淺出學Hive
- 類別:文學
- 頁數:98
- 定價:12
- 裝幀:平裝
- 開本:16
作品目錄,內容介紹,第一部分:Hadoop計算框架的特性,第二部分:最佳化的常用手段,第三部分:Hive的數據類型方面的最佳化,控制Hive的Map數,合併MapReduce操作,
作品目錄
內容介紹
第一部分:Hadoop計算框架的特性
什麼是數據傾斜
·由於數據的不均衡原因,導致數據分布不均勻,造成數據大量的集中到一點,造成數據熱點
Hadoop框架的特性
·不怕數據大,怕數據傾斜
·jobs數比較多的作業運行效率相對比較低,比如即使有幾百行的表,如果多次關聯多次匯總,產生十幾個jobs,耗時很長。原因是mapreduce作業初始化的時間是比較長的
·sum,count,max,min等UDAF,不怕數據傾斜問題,hadoop在map端的匯總合併最佳化,使數據傾斜不成問題
·count(distinct),在數據量大的情況下,效率較低,因為count(distinct)是按groupby欄位分組,按distinct欄位排序,一般這種分布方式是很傾斜的
·由於數據的不均衡原因,導致數據分布不均勻,造成數據大量的集中到一點,造成數據熱點
Hadoop框架的特性
·不怕數據大,怕數據傾斜
·jobs數比較多的作業運行效率相對比較低,比如即使有幾百行的表,如果多次關聯多次匯總,產生十幾個jobs,耗時很長。原因是mapreduce作業初始化的時間是比較長的
·sum,count,max,min等UDAF,不怕數據傾斜問題,hadoop在map端的匯總合併最佳化,使數據傾斜不成問題
·count(distinct),在數據量大的情況下,效率較低,因為count(distinct)是按groupby欄位分組,按distinct欄位排序,一般這種分布方式是很傾斜的
第二部分:最佳化的常用手段
最佳化的常用手段
·解決數據傾斜問題
·減少job數
·設定合理的mapreduce的task數,能有效提升性能。
·了解數據分布,自己動手解決數據傾斜問題是個不錯的選擇
·數據量較大的情況下,慎用count(distinct)。
·對小檔案進行合併,是行至有效的提高調度效率的方法。
·最佳化時把握整體,單個作業最優不如整體最優。
·解決數據傾斜問題
·減少job數
·設定合理的mapreduce的task數,能有效提升性能。
·了解數據分布,自己動手解決數據傾斜問題是個不錯的選擇
·數據量較大的情況下,慎用count(distinct)。
·對小檔案進行合併,是行至有效的提高調度效率的方法。
·最佳化時把握整體,單個作業最優不如整體最優。
第三部分:Hive的數據類型方面的最佳化
最佳化原則
·按照一定規則分區(例如根據日期)。通過分區,查詢的時候指定分區,會大大減少在無用數據上的掃描,同時也非常方便數據清理。
·合理的設定Buckets。在一些大數據join的情況下,mapjoin有時候會記憶體不夠。如果使用BucketMapJoin的話,可以只把其中的一個bucket放到記憶體中,記憶體中原來放不下的記憶體表就變得可以放下。這需要使用buckets的鍵進行join的條件連結,並且需要如下設定
sethive.optimize.bucketmapjoin=true
第四部分:Hive的操作方面的最佳化
·全排序
·怎樣做笛卡爾積
·怎樣決定map個數
·怎樣決定reducer個數
·合併MapReduce操作
·Bucket與sampling
·Partition
·JOIN
·GroupBy
·合併小檔案
全排序
·Hive的排序關鍵字是SORTBY,它有意區別於傳統資料庫的ORDERBY也是為了強調兩者的區別–SORTBY只能在單機範圍內排序
怎樣做笛卡爾積
·當Hive設定為嚴格模式(hive.mapred.mode=strict)時,不允許在HQL語句中出現笛卡爾積
·MapJoin是的解決辦法
·MapJoin,顧名思義,會在Map端完成Join操作。這需要將Join操作的一個或多個表完全讀入記憶體
·MapJoin的用法是在查詢/子查詢的SELECT關鍵字後面添加/*+MAPJOIN(tablelist)*/提示最佳化器轉化為MapJoin(目前Hive的最佳化器不能自動最佳化MapJoin)
·其中tablelist可以是一個表,或以逗號連線的表的列表。tablelist中的表將會讀入記憶體,應該將小表寫在這裡
·在大表和小表做笛卡爾積時,規避笛卡爾積的方法是,給Join添加一個Joinkey,原理很簡單:將小表擴充一列joinkey,並將小表的條目複製數倍,joinkey各不相同;將大表擴充一列joinkey為隨機數
·按照一定規則分區(例如根據日期)。通過分區,查詢的時候指定分區,會大大減少在無用數據上的掃描,同時也非常方便數據清理。
·合理的設定Buckets。在一些大數據join的情況下,mapjoin有時候會記憶體不夠。如果使用BucketMapJoin的話,可以只把其中的一個bucket放到記憶體中,記憶體中原來放不下的記憶體表就變得可以放下。這需要使用buckets的鍵進行join的條件連結,並且需要如下設定
sethive.optimize.bucketmapjoin=true
第四部分:Hive的操作方面的最佳化
·全排序
·怎樣做笛卡爾積
·怎樣決定map個數
·怎樣決定reducer個數
·合併MapReduce操作
·Bucket與sampling
·Partition
·JOIN
·GroupBy
·合併小檔案
全排序
·Hive的排序關鍵字是SORTBY,它有意區別於傳統資料庫的ORDERBY也是為了強調兩者的區別–SORTBY只能在單機範圍內排序
怎樣做笛卡爾積
·當Hive設定為嚴格模式(hive.mapred.mode=strict)時,不允許在HQL語句中出現笛卡爾積
·MapJoin是的解決辦法
·MapJoin,顧名思義,會在Map端完成Join操作。這需要將Join操作的一個或多個表完全讀入記憶體
·MapJoin的用法是在查詢/子查詢的SELECT關鍵字後面添加/*+MAPJOIN(tablelist)*/提示最佳化器轉化為MapJoin(目前Hive的最佳化器不能自動最佳化MapJoin)
·其中tablelist可以是一個表,或以逗號連線的表的列表。tablelist中的表將會讀入記憶體,應該將小表寫在這裡
·在大表和小表做笛卡爾積時,規避笛卡爾積的方法是,給Join添加一個Joinkey,原理很簡單:將小表擴充一列joinkey,並將小表的條目複製數倍,joinkey各不相同;將大表擴充一列joinkey為隨機數
控制Hive的Map數
·通常情況下,作業會通過input的目錄產生一個或者多個map任務
·主要的決定因素有:input的檔案總個數,input的檔案大小,集群設定的檔案塊大小(目前為128M,可在hive中通過setdfs.block.size;命令查看到,該參數不能自定義修改)
·是不是map數越多越好
答案是否定的。如果一個任務有很多小檔案(遠遠小於塊大小128m),則每個小檔案也會被當做一個塊,用一個map任務來完成,
而一個map任務啟動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費。
而且,同時可執行的map數是受限的
·是不是保證每個map處理接近128m的檔案塊,就高枕無憂了?
答案也是不一定。比如有一個127m的檔案,正常會用一個map去完成,但這個檔案只有一個或者兩個小欄位,卻有幾千萬的記錄,
如果map處理的邏輯比較複雜,用一個map任務去做,肯定也比較耗時。
針對上面的問題3和4,我們需要採取兩種方式來解決:即減少map數和增加map數;
·是不是保證每個map處理接近128m的檔案塊,就高枕無憂了?
答案也是不一定。比如有一個127m的檔案,正常會用一個map去完成,但這個檔案只有一個或者兩個小欄位,卻有幾千萬的記錄,
如果map處理的邏輯比較複雜,用一個map任務去做,肯定也比較耗時。
針對上面的問題3和4,我們需要採取兩種方式來解決:即減少map數和增加map數;
·舉例
a)假設input目錄下有1個檔案a,大小為780M,那么hadoop會將該檔案a分隔成7個塊(6個128m的塊和1個12m的塊),從而產生7個map數
b)假設input目錄下有3個檔案a,b,c,大小分別為10m,20m,130m,那么hadoop會分隔成4個塊(10m,20m,128m,2m),從而產生4個map數
即,如果檔案大於塊大小(128m),那么會拆分,如果小於塊大小,則把該檔案當成一個塊
怎樣決定reducer個數
·HadoopMapReduce程式中,reducer個數的設定極大影響執行效率
·不指定reducer個數的情況下,Hive會猜測確定一個reducer個數,基於以下兩個設定:
參數1:hive.exec.reducers.bytes.per.reducer(默認為1G)
參數2:hive.exec.reducers.max(默認為999)
·計算reducer數的公式
·N=min(參數2,總輸入數據量/參數1)
·依據Hadoop的經驗,可以將參數2設定為0.95*(集群中TaskTracker個數)
·reduce個數並不是越多越好
同map一樣,啟動和初始化reduce也會消耗時間和資源;
另外,有多少個reduce,就會有多少個輸出檔案,如果生成了很多個小檔案,那么如果這些小檔案作為下一個任務的輸入,則也會出現小檔案過多的問題
·什麼情況下只有一個reduce
很多時候你會發現任務中不管數據量多大,不管你有沒有設定調整reduce個數的參數,任務中一直都只有一個reduce任務;
其實只有一個reduce任務的情況,除了數據量小於
hive.exec.reducers.bytes.per.reducer參數值的情況外,還有以下原因:
a)沒有groupby的匯總
b)用了Orderby
·主要的決定因素有:input的檔案總個數,input的檔案大小,集群設定的檔案塊大小(目前為128M,可在hive中通過setdfs.block.size;命令查看到,該參數不能自定義修改)
·是不是map數越多越好
答案是否定的。如果一個任務有很多小檔案(遠遠小於塊大小128m),則每個小檔案也會被當做一個塊,用一個map任務來完成,
而一個map任務啟動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費。
而且,同時可執行的map數是受限的
·是不是保證每個map處理接近128m的檔案塊,就高枕無憂了?
答案也是不一定。比如有一個127m的檔案,正常會用一個map去完成,但這個檔案只有一個或者兩個小欄位,卻有幾千萬的記錄,
如果map處理的邏輯比較複雜,用一個map任務去做,肯定也比較耗時。
針對上面的問題3和4,我們需要採取兩種方式來解決:即減少map數和增加map數;
·是不是保證每個map處理接近128m的檔案塊,就高枕無憂了?
答案也是不一定。比如有一個127m的檔案,正常會用一個map去完成,但這個檔案只有一個或者兩個小欄位,卻有幾千萬的記錄,
如果map處理的邏輯比較複雜,用一個map任務去做,肯定也比較耗時。
針對上面的問題3和4,我們需要採取兩種方式來解決:即減少map數和增加map數;
·舉例
a)假設input目錄下有1個檔案a,大小為780M,那么hadoop會將該檔案a分隔成7個塊(6個128m的塊和1個12m的塊),從而產生7個map數
b)假設input目錄下有3個檔案a,b,c,大小分別為10m,20m,130m,那么hadoop會分隔成4個塊(10m,20m,128m,2m),從而產生4個map數
即,如果檔案大於塊大小(128m),那么會拆分,如果小於塊大小,則把該檔案當成一個塊
怎樣決定reducer個數
·HadoopMapReduce程式中,reducer個數的設定極大影響執行效率
·不指定reducer個數的情況下,Hive會猜測確定一個reducer個數,基於以下兩個設定:
參數1:hive.exec.reducers.bytes.per.reducer(默認為1G)
參數2:hive.exec.reducers.max(默認為999)
·計算reducer數的公式
·N=min(參數2,總輸入數據量/參數1)
·依據Hadoop的經驗,可以將參數2設定為0.95*(集群中TaskTracker個數)
·reduce個數並不是越多越好
同map一樣,啟動和初始化reduce也會消耗時間和資源;
另外,有多少個reduce,就會有多少個輸出檔案,如果生成了很多個小檔案,那么如果這些小檔案作為下一個任務的輸入,則也會出現小檔案過多的問題
·什麼情況下只有一個reduce
很多時候你會發現任務中不管數據量多大,不管你有沒有設定調整reduce個數的參數,任務中一直都只有一個reduce任務;
其實只有一個reduce任務的情況,除了數據量小於
hive.exec.reducers.bytes.per.reducer參數值的情況外,還有以下原因:
a)沒有groupby的匯總
b)用了Orderby
合併MapReduce操作
·Multi-groupby
·Multi-groupby是Hive的一個非常好的特性,它使得Hive中利用中間結果變得非常方便
·FROMlog
·insertoverwritetabletest1selectlog.idgroupbylog.id
·insertoverwritetabletest2selectlog.namegroupbylog.name
·上述查詢語句使用了Multi-groupby特性連續groupby了2次數據,使用不同的groupbykey。這一特性可以減少一次MapReduce操作。
Bucket與Sampling
·Bucket是指將數據以指定列的值為key進行hash,hash到指定數目的桶中。這樣就可以支持高效採樣了
·Sampling可以在全體數據上進行採樣,這樣效率自然就低,它還是要去訪問所有數據。而如果一個表已經對某一列製作了bucket,就可以採樣所有桶中指定序號的某個桶,這就減少了訪問量。
·如下例所示就是採樣了test中32個桶中的第三個桶。
·SELECT*FROMtest、、、TABLESAMPLE(BUCKET3OUTOF32);
JOIN原則
·在使用寫有Join操作的查詢語句時有一條原則:應該將條目少的表/子查詢放在Join操作符的左邊
·原因是在Join操作的Reduce階段,位於Join操作符左邊的表的內容會被載入進記憶體,將條目少的表放在左邊,可以有效減少發生OOM錯誤的幾率
MapJoin
·Join操作在Map階段完成,不再需要Reduce,前提條件是需要的數據在Map的過程中可以訪問到
·例如:
·INSERTOVERWRITETABLEphone_traffic
SELECT/*+MAPJOIN(phone_location)*/l.phone,p.location,l.trafficfromphone_locationpjoinloglon(p.phone=l.phone)
·相關的參數為:
hive.join.emit.interval=1000Howmanyrowsintheright-mostjoinoperandHiveshouldbufferbeforeemittingthejoinresult.
hive.mapjoin.size.key=10000
hive.mapjoin.cache.numrows=10000
GroupBy
·Map端部分聚合
·並不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進行部分聚合,最後在Reduce端得出最終結果
·基於Hash
·參數包括:
·hive.map.aggr=true是否在Map端進行聚合,默認為True
·hive.groupby.mapaggr.checkinterval=100000在Map端進行聚合操作的條目數目
·有數據傾斜的時候進行負載均衡
·hive.groupby.skewindata=false
·當選項設定為true,生成的查詢計畫會有兩個MRJob。第一個MRJob中,Map的輸出結果集合會隨機分布到Reduce中,每個Reduce做部分聚合操作,並輸出結果,這樣處理的結果是相同的GroupByKey有可能被分發到不同的Reduce中,從而達到負載均衡的目的;第二個MRJob再根據預處理的數據結果按照GroupByKey分布到Reduce中(這個過程可以保證相同的GroupByKey被分布到同一個Reduce中),最後完成最終的聚合操作。
合併小檔案
·檔案數目過多,會給HDFS帶來壓力,並且會影響處理效率,可以通過合併Map和Reduce的結果檔案來消除這樣的影響:
·hive.merge.mapfiles=true是否和並Map輸出檔案,默認為True
·hive.merge.mapredfiles=false是否合併Reduce輸出檔案,默認為False
·hive.merge.size.per.task=256*1000*1000合併檔案的大小