真正讓你明白Hive調優系列3:笛卡爾乘積,小表join大表,Mapjoin等問題

0.Hive中的優化分類

     真正想要掌握Hive的優化,要熟悉相關的MapReduce,Yarn,hdfs底層源碼,明晰Hive的底層執行流程。真正讓你明白Hive調優系列,會徵對下面分類逐一分析演示。

大類1:參數優化

  1. 文件輸入前看是否需要map前合併小文件
  2. 控制map個數,根據實際需求確認每個map的數據處理量,split的參數等
  3. Map輸出是否需要啓動壓縮,減少網絡傳輸,OOM處理等
  4. 控制redcue個數,控制每個reduce的吞吐量,OOM處理等
  5. 是否將common-join轉換成map-join處理策略
  6. 文件輸出是否需要啓動小文件合併策略
  7. 其他相關參數的配置:如嚴格模式,JVM重用,列剪切等

大類2:開發中優化

  1. 數據傾斜,這個是Hive優化的重頭戲。出現的原因是因爲出現了數據的重新分發和分佈,啓動了redcue。Hive中數據傾斜分類:group by ,count(distinct)以及join產生的數據傾斜(當然一些窗口函數中用了partition by一會造成數據傾斜)
  2. join相關的優化:分類大表join大表,小表join大表的優化
  3. 代碼細節優化分類比如去重用group by替代distinct ;多表關聯,先進行子查詢後再進行關聯;表關聯時一定要在子查詢裏過濾掉NULL值,避免數據傾斜;不要對一個表進行重複處理,多使用臨時表,儘量做到一次處理多次使用等等,

1.笛卡爾乘積與小表join大表

 Hive 設定爲嚴格模式(hive.mapred.mode=strict)時,不允許在 HQL 語句中出現笛卡爾積, 這實際說明了 Hive 對笛卡爾積支持較弱。因爲找不到 Join key,Hive 只能使用 1 個 reducer 來完成笛卡爾積。

需求1一個小表join大表,且兩個表特殊的是笛卡爾乘積(on true/on 1=1)。小表的數據量2Mb,大表的數據是4Gb左右。實際開發中該段代碼跑了3個小時左右


drop table if exists FDM_TMP.TMP_FSA_MULTI_PATH_FUNL_ANALYSE_RSLT_D_21_${hivevar:statis_date};
CREATE TABLE IF NOT EXISTS FDM_TMP.TMP_FSA_MULTI_PATH_FUNL_ANALYSE_RSLT_D_21_${hivevar:statis_date}
stored as rcfile as
SELECT T1.ACCT_NO                                              
       ,T1.PAGE_ID                                                 
       ,T1.PAGE_NAME                                               
       ,T1.PAGE_URL                 
       ,T1.TRMNL_TYPE                                              
       ,T1.DEV_ID 
       ,T0.PATH_ID                                               
       ,T0.UBA_HRCHY        
       ,T0.UBA_HRCHY_LO     
       ,T0.TRANS_CYCLE
       ,T0.TRANS_RATE_CALC
       ,T0.CUS_GROUP_NO
       ,T1.SYS_TYPE
  from fdm_tmp.tmp_fsa_multi_path_funl_analyse_rslt_d_01_${hivevar:statis_date} t0   ---小表大概2Mb左右
 inner join FDM_DPA.FSA_MULTI_PATH_FUNL_VISIT_URL_HIS_D t1           ----大表大概3.4G
    on 1=1                                             ----------笛卡爾乘積
   and t0.comp_cond_type='10010201'  --等於
   and t0.path_cond_type = '60020204'         --頁面名稱
   and t0.UBA_HRCHY= '1' --第一層
 where t1.stat_date<='${statisdate}'
   and t1.stat_date>=t0.trans_cycle  --已將轉換週期轉換成對應的起始日期
   and (t0.Page_Name = t1.page_name  or t1.page_id =t0.page_name)
 group by t1.acct_no           
          ,t1.Page_ID          
          ,t1.Page_Name        
          ,t1.page_url         
          ,t1.TRMNL_TYPE           
          ,t1.Dev_ID 
          ,t0.path_id              
          ,t0.UBA_HRCHY      
          ,t0.UBA_HRCHY_LO 
          ,t0.trans_cycle
          ,t0.trans_rate_calc
          ,T0.CUS_GROUP_NO
          ,t1.SYS_TYPE
;

優化使用:配置如下參數,使用mapjoin替代common join.當然這裏因爲group by的原因還是會啓動reduce進行去重。但是整體從4個小時優化到1.5小時。一般來說小表join大表一般配置下面四個參數就差不多,當然官方還提供了其他的參數共配置。Hive官網參數配置

  1. set hive.auto.convert.join = true ;   -- hive是否自動根據文件量大小,選擇將common join轉成map join 。hive 0.10 版本後的默認值 true。
  2. set  hive.mapjoin.smalltable.filesize =25000000 ;大表小表判斷的閾值,如果表的大小小於該值25Mb,則會被判定爲小表。則會被加載到內存中運行,將commonjoin轉化成mapjoin。一般這個值也就最多幾百兆的樣子。
  3. set  hive.auto.convert.join.noconditionaltask = true;  翻譯官網的解釋:是否啓用基於輸入文件的大小,將普通連接轉化爲Map連接的優化機制。假設參與連接的表(或分區)有N個,如果打開這個參數,並且有N-1個表(或分區)的大小總和小於hive.auto.convert.join.noconditionaltask.size參數指定的值,那麼會直接將連接轉爲Map連接。(說人話:默認值:true,當將普通的join轉化爲普通的mapjoin時,是否將多個mapjoin轉化爲一個mapjoin,主要針對多個小表join大表的情形)
  4. set  hive.auto.convert.join.noconditionaltask.size =10000000; 翻譯官網:如果hive.auto.convert.join.noconditionaltask是關閉的,則本參數不起作用。否則,如果參與連接的N個表(或分區)中的N-1個 的總大小小於這個參數的值,則直接將連接轉爲Map連接。默認值爲10MB。(說人話:將多個mapjoin轉化爲一個mapjoin時,其小表總和的最大值,所以這個條件比單獨啓動一個mapjon的參數set  hive.mapjoin.smalltable.filesize更加嚴格。

尖叫提示:

1.一般遇到小表join大表,不管是多少個小表,把小表寫在前面,開啓mapjon,同時適當地調大上面的參數,Mapjoin幾乎是解決小表join大表(包括笛卡爾乘積)的最好方式。尤其對於笛卡爾乘積的小表join大表來說,性能差別天壤之別。

2.所謂的mapjoin優化就是在Map階段完成join工作,而不是像通常的common join在Reduce階段按照join的列值進行分發數據到每個Reduce上進行join工作。前面我們知道,沒有數據分發分佈也就不會有數據傾斜的存在。實際上所謂的mapjoin並不是像有些人說的那樣只是將小表加載到內存然後跟大表join那麼簡單,如果那樣照樣會有reduce的產生,也不會快那麼多。而是會將所有的小表全量複製到每個map任務節點,然後再將小表緩存在每個map節點的內存裏與大表進行join工作。所以這解釋了爲啥小表的大小的不能太大的原因,否則複製分發太多反而得不償失。一般這個值也就幾百兆吧。像我們公司每個map的分配的內存才2G,堆內存才1.5G,你要是搞個1個G的小表,直接很容易OOM報錯了。

3.在0.7.0版本之前:需要在sql中使用 /*+ MAPJOIN(smallTable) */ 來開啓mapjoin,而後則Hive會自動通過配置的參數來判斷是否開啓mapjoin。

4.對於小表join大表的笛卡爾乘積,還可以通過規避的方法避免:具體比如給 Join的兩個表都增加一列Join key原理很簡單:將小表擴充一列join key,並將小表的總數複製數倍,join key 各不相同,比如第一次爲1,複製一次joinkey爲2,依次類推;將大表擴充一列join key 爲隨機數,這個隨機數爲小表裏的joinkey的隨機值,如1-5的隨機值。這樣就實現了將一個大表拆分幾分同時處理,而且這樣小表擴充了幾倍,大表就被對應地分成幾份處理。這種方式也可以提高笛卡爾乘積小表join大表的性能。

2.笛卡爾乘積:大表join大表

       大表join大表一般調優有四種方式具體參考其他博客,但是對於笛卡爾乘積來說,如果是小join大,開啓mapjoin性能還不算太差,但要是大join大的笛卡爾乘積那是真可怕。

1.首先要儘量避免笛卡爾乘積,比如HQL無法支持循環,遍歷等缺陷,這種情況遇到笛卡爾乘積的可以考慮用spark來替代,或者用UDF來解決,這是首選方案,其他幾乎沒有更好的處理方案了。

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