Hive SQL 優化

要想做好hive優化,首先要理解MR過程,HiveSQL轉換爲MR的過程,以及Hive表的分區分桶機制。

本質上的優化是,減少讀,避免shuffle 和 增加併發度。

優化的手段:

跳過不必要的讀 減少Shuffle 讀延遲問題 數據傾斜
Partition、Bucket 使用 Skew(hive對聲明瞭Skew的列會單獨使用文件存儲,並且在資源分配上有優待) MapJoin(Broadcast Join),避免ReduceJoin 增加熱數據備份數 對於傾斜部分單獨拿出來,做Map Join
ORCFile => 支持只讀需要的列 Sort-Merge-Bucket Join 啓動短路讀(Short-Circuit Read),即不通過網絡客戶端,而是直接讀取本地文件 將傾斜Key綁定一個隨機數R,先按key、R做一次Shuffle,聚合減少數據量,然後再按Key做Shuffle聚合。
使用Tez

Shuffle Sort/ Map Reduce 原理理解

Map Shuffle 過程:

(1)讀取block,並切分爲多個split,每個split對應一個map task。

(2)按Key 進行 Partition,內存排序,排序結果放入緩存,緩存不夠發生溢寫。

(3)溢寫文件和內存中數據最終歸併排序輸出Map的結果,最後合併成了一個已分區且已排序的文件。

Reduce Shuffle 過程:

(1)Reduce Task 通過Copy方式,拉取Map task輸出的文件,每次傳輸來的數據都是有序的。

(2)拉取的數據寫緩存,緩存不夠造成溢寫。

(3)每個Ruduce任務,會直接將各個溢寫的文件歸併排序的結果作爲輸入,產出reudce的結果。

Hive SQL To Mapreduce 過程(感謝美團團隊整理)

Join的實現原理

使用Join 關聯的字段作爲Key,併爲Value打上不同的表來源標識。

在map的輸出value中爲不同表的數據打上tag標記,在reduce階段根據tag判斷數據來源。MapReduce的過程如下 (這裏只是說明最基本的Join的實現,還有其他的實現方式)

Group By的實現原理

Group By 的字段組合作爲Key,並且Map端預聚合

select rank, isonline, count(*) from city group by rank, isonline; 將GroupBy的字段組合爲map的輸出key值,利用MapReduce的排序,在reduce階段保存LastKey區分不同的 key。MapReduce的過程如下(當然這裏只是說明Reduce端的非Hash聚合過程)

Distinct的實現原理

單個distinct,使用group字段和distinct字段作爲排序Key,Group字段作爲分區Key,在Reduce階段保存LastKey(因爲排序後每組是按key有序的,因此只需使用一個LastKey作爲去重字段)

select dealid, count(distinct uid) num from order group by dealid;

當只有一個distinct字段時,如果不考慮Map階段的Hash GroupBy,只需要將GroupBy字段和Distinct字段組合爲 map輸出key,利用mapreduce的排序,同時將GroupBy字段作爲reduce的key,在reduce階段保存LastKey即可完成去 重

如果有多個distinct字段呢,如下面的SQL select dealid, count(distinct uid), count(distinct date) from order group by dealid;

實現方式有兩種:

(1)和單個Distinct相同,但是內存階段通過Hash去重。

如果仍然按照上面一個distinct字段的方法,即下圖這種實現方式,無法跟據uid和date分別排序,也就無法 通過LastKey去重,仍然需要在reduce階段在內存中通過Hash去重

(2)對所有的distinct字段編號,每行數據生成n行數據,按單個distinct進行處理。

第二種實現方式,可以對所有的distinct字段編號,每行數據生成n行數據,那麼相同字段就會分別排序,這 時只需要在reduce階段記錄LastKey即可去重。 這種實現方式很好的利用了MapReduce的排序,節省了reduce階段去重的內存消耗,但是缺點是增加了shuffle的數 據量。 需要注意的是,在生成reduce value時,除第一個distinct字段所在行需要保留value值,其餘distinct數據行 value字段均可爲空。

理解 查詢語句中 Cluster By,Distribute By,Sort By 和 Order By

Cluster By col = 按 col 列 Distribute By + Sort By。

Distribut By  col1  和 Sort By col2 通常聯合使用,是指的按col1 Partition 並且 按 col2 組內排序。

Order By 是指的全局有序,只有一個Reducer。

理解 建表語句中的Clustered By 、Sorted By 和 Skewed By

Clustered by 是插入數據是按某些列進行分Bucket(文件級別),而Sorted By 是按某些列全局排序,並分桶。

Skewed By 是對傾斜列做特殊處理,單獨文件存儲。

HIve 優化的方向

跳過不必要的讀 減少Shuffle 讀延遲問題
Partition、Bucket 使用 Skew(hive對聲明瞭Skew的列會單獨使用文件存儲,並且在資源分配上有優待) MapJoin(Broadcast Join),避免ReduceJoin 增加熱數據備份數
ORCFile => 支持只讀需要的列 Sort-Merge-Bucket Join 啓動短路讀(Short-Circuit Read)
使用Tez

Map Side Join

MapJoin簡單說就是在Map階段將小表讀入內存,順序掃描大表完成Join。

MapJoin簡單說就是在Map階段將小表讀入內存,順序掃描大表完成Join。 上圖是Hive MapJoin的原理圖,出自Facebook工程師Liyin Tang的一篇介紹Join優化的slice,從圖中可以看出 MapJoin分爲兩個階段: 1. 通過MapReduce Local Task,將小表讀入內存,生成HashTableFiles上傳至Distributed Cache中,這裏會對 HashTableFiles進行壓縮。 2. MapReduce Job在Map階段,每個Mapper從Distributed Cache讀取HashTableFiles到內存中,順序掃描大表,在Map 階段直接進行Join,將數據傳遞給下一個MapReduce任務

SET hive.auto.convert.join=true;
SET hive.mapjoin.smalltable.filesize = 20000000
Select /*+ mapjoin(tablelist) */

Bucket mapjoin

1) set hive.optimize.bucketmapjoin = true;
2) 一個表的bucket數是另一個表bucket數的整數倍:即一個大表,一個小表
3) bucket列 == join列
4) 必須是應用在map join的場景中

在這種情況下,大表和小表都是按Key分桶的,且大表的桶數是小標的n倍,這樣,就可以n個大表桶,對應1個小表桶,將1個小表桶做廣播到n個大表桶,做Map Side Join。

SMB join (針對bucket mapjoin 的一種優化)

1)
set hive.auto.convert.sortmerge.join=true;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.auto.convert.sortmerge.join.noconditionaltask=true;

set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputF ormat;

2) 小表的bucket數=大表bucket數
3) Bucket 列 == Join 列 == sort 列
4) 必須是應用在bucket mapjoin 的場景中

在這種情況下,桶數相同,且每桶的key都是排序的,因此在讀入Mapper時,相同的Key一定出現在同一個Map中,相當於Shuffle sort之後的Reudce過程,可以做Map Side Join。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yhyQx3tY-1591253004454)(http://cdn.rabbitai.cn/hive/13.png)]

Skew(傾斜) 優化

數據傾斜的核心思想,是在Map Shuffle階段,就統計出需要單獨做Map Join 的Key,把傾斜的部分拿出來,單獨做Map Side Join,不走reduce Shuffle。

select A.id from A join B on A.id = B.id
-- 轉化爲,傾斜部分和非傾斜部分
 select A.id from A join B on A.id = B.id where A.id <> 1;
 select A.id from A join B on A.id = B.id where A.id = 1 and B.id = 1;
-- 如果建表語句元數據中指定了skew key,則使用set hive.optimize.skewjoin.compiletime=true開啓skew join。
CREATE TABLE list_bucket_single (key STRING, value STRING) SKEWED BY (key)
ON (1,5,6);
-- 在運行時動態指定數據進行skewjoin,一般和hive.skewjoin.key參數一起使用
set hive.optimize.skewjoin = true; 
set hive.skewjoin.key =100000
-- 以上參數表示當記錄條數超過100000時採用skewjoin操作

### group by 傾斜優化

對於確定的傾斜值,先均勻分佈到各個reducer上,然後開啓新一輪reducer進行統計操作。寫法如下

 -- 正常寫法
  select key
       , count(1) as cnt
    from tb_name
   group  by  key;-- 改進後寫法
  select a.key
       , sum(cnt) as cnt
   from (select key
              , if(key = 'key001',random(),0)
              , count(1) as cnt
           from tb_name
          group by key, 
                   if(key = 'key001',random(),0)
         ) t
   group by t.key;

如果在不確定傾斜值的情況下,可以設置hive.groupby.skewindata參數,其原理和上述寫法調整中類似,是先對key值進行均勻分佈,然後開啓新一輪reducer求值

set hive.groupby.skewindata=true;
  select key
       , count(1) as cnt
    from tb_name
   group by key;

參考:

Antlr: http://www.antlr.org/

Wiki Antlr介紹: http://en.wikipedia.org/wiki/ANTLR

Hive Wiki: https://cwiki.apache.org/confluence/display/Hive/Home

HiveSQL編譯過程: http://www.slideshare.net/recruitcojp/internal-hive

Join Optimization in Hive: Join Strategies in Hive from the 2011 Hadoop Summit (Liyin Tang, Namit Jain) Hive Design Docs: https://cwiki.apache.org/confluence/display/Hive/DesignDocs

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章