1. 程式人生 > >hive大小表join優化效能

hive大小表join優化效能

摘要: MAPJOIN 當一個大表和一個或多個小表做JOIN時,最好使用MAPJOIN,效能比普通的JOIN要快很多。 另外,MAPJOIN 還能解決資料傾斜的問題。 MAPJOIN的基本原理是:在小資料量情況下,SQL會將使用者指定的小表全部載入到執行JOIN操作的程式的記憶體中,從而加快JOIN的執行速度。

1、小、大表 join

在小表和大表進行join時,將小表放在前邊,效率會高。hive會將小表進行快取。

2、mapjoin

使用mapjoin將小表放入記憶體,在map端和大表逐一匹配。從而省去reduce。

樣例:

select /*+MAPJOIN(b)*/ a.a1,a.a2,b.b2 from tablea a JOIN tableb b ON a.a1=b.b1

快取多張小表:
select /*+MAPJOIN(b,c)*/ a.a1,a.a2,b.b2 from tablea a JOIN tableb b ON a.a1=b.b1 JOIN tbalec c on a.a1=c.c1
mapjoin的join發生在map階段,join的join發生在reduce階段,mapjoin可以提高效率

使用

方法一:

在Hive0.11前,必須使用MAPJOIN來標記顯示地啟動該優化操作,由於其需要將小表載入進記憶體所以要注意小表的大小

SELECT /*+ MAPJOIN(smalltable)*/  .key,value
FROM smalltable JOIN bigtable ON smalltable.key = bigtable.key

方法二

在Hive0.11後,Hive預設啟動該優化,也就是不在需要顯示的使用MAPJOIN標記,其會在必要的時候觸發該優化操作將普通JOIN轉換成MapJoin,可以通過以下兩個屬性來設定該優化的觸發時機

hive.auto.convert.join

預設值為true,自動開戶MAPJOIN優化

hive.mapjoin.smalltable.filesize

預設值為2500000(25M),通過配置該屬性來確定使用該優化的表的大小,如果表的大小小於此值就會被載入進記憶體中

 

注意:使用預設啟動該優化的方式如果出現默名奇妙的BUG(比如MAPJOIN並不起作用),就將以下兩個屬性置為fase手動使用MAPJOIN標記來啟動該優化

hive.auto.convert.join=false(關閉自動MAPJOIN轉換操作)
hive.ignore.mapjoin.hint=false(不忽略MAPJOIN標記)

 

對於以下查詢是不支援使用方法二(MAPJOIN標記)來啟動該優化的

select /*+MAPJOIN(smallTableTwo)*/ idOne, idTwo, value FROM
  ( select /*+MAPJOIN(smallTableOne)*/ idOne, idTwo, value FROM
    bigTable JOIN smallTableOne on (bigTable.idOne = smallTableOne.idOne)                                                  
  ) firstjoin                                                            
  JOIN                                                                 
  smallTableTwo ON (firstjoin.idTwo = smallTableTwo.idTwo)  

但是,如果使用的是方法一即沒有MAPJOIN標記則以上查詢語句將會被作為兩個MJ執行,進一步的,如果預先知道表大小是能夠被載入進記憶體的,則可以通過以下屬性來將兩個MJ合併成一個MJ

hive.auto.convert.join.noconditionaltask:Hive在基於輸入檔案大小的前提下將普通JOIN轉換成MapJoin,並是否將多個MJ合併成一個
hive.auto.convert.join.noconditionaltask.size:多個MJ合併成一個MJ時,其表的總的大小須小於該值,同時hive.auto.convert.join.noconditionaltask必須為true

MAPJOIN

當一個大表和一個或多個小表做JOIN時,最好使用MAPJOIN,效能比普通的JOIN要快很多。 另外,MAPJOIN 還能解決資料傾斜的問題。
MAPJOIN的基本原理是:在小資料量情況下,SQL會將使用者指定的小表全部載入到執行JOIN操作的程式的記憶體中,從而加快JOIN的執行速度。
使用MAPJOIN時,需要注意:

  • LEFT OUTER JOIN的左表必須是大表;
  • RIGHT OUTER JOIN的右表必須是大表;
  • INNER JOIN左表或右表均可以作為大表;
  • FULL OUTER JOIN不能使用MAPJOIN;
  • MAPJOIN支援小表為子查詢;
  • 使用MAPJOIN時需要引用小表或是子查詢時,需要引用別名;
  • 在MAPJOIN中,可以使用不等值連線或者使用OR連線多個條件;
  • 目前ODPS在MAPJOIN中最多支援指定6張小表,否則報語法錯誤;
  • 如果使用MAPJOIN,則所有小表佔用的記憶體總和不得超過512M(解壓後的邏輯資料量)。

MAPJOIN 判定邏輯:

同時滿足下面2個條件:
1) Join階段 max(join instance 執行時間) > 10分鐘 && max( join instance 執行時間 ) > 2 * avg( join instance 執行時間 )
2) 參與join 的最小表資料量小於100M (解壓前的邏輯資料量)

MAPJOIN 記憶體自定義設定:

set odps.sql.mapjoin.memory.max=512
設定mapjoin時小表的最大記憶體,預設512,單位M,[128,2048]之間調整

舉例

這個例子比較綜合,既涉及到了資料傾斜問題,又涉及到當“小表”不是很小時(>512M)如何利用mapjoin.
場景:

  select * from log a
  left outer join users b
  on a.user_id = b.user_id;

日誌表(log)通常來說是記錄數比較多的,但使用者表(users)也不小,600W+ 的記錄,把 users 分發到所有的 map 上也是個不小的開銷,而且 map join 不支援這麼大的小表。如果用普通的 join,又會碰到資料傾斜的問題。
解決方法:

  select /*+mapjoin(b)*/
  * 
  from log a
  left outer join (
    select  /*+mapjoin(c)*/
    d.*
    from ( select distinct user_id from log ) c
    join users d
    on c.user_id = d.user_id
    ) b
  on a.user_id = b.user_id;

這種解決方法的前提場景是:每日的會員uv不會太多,即 log 表中的 count(distinct user_id) 不會太大。