Hive 如何使用mapjoin
hive mapjoin使用
今天遇到一個hive的問題,如下hive sql:
select f.a,f.b from A t join B f on ( f.a=t.a and f.ftime=20110802)
該語句中B表有30億行記錄,A表只有100行記錄,而且B表中數據傾斜特別嚴重,有一個key上有15億行記錄,在運行過程中特別的慢,而且在reduece的過程中遇有內存不夠而報錯。
為了解決用戶的這個問題,考慮使用mapjoin,mapjoin的原理:
MAPJION會把小表全部讀入內存中,在map階段直接拿另外一個表的數據和內存中表數據做匹配,由於在map是進行了join操作,省去了reduce運行的效率也會高很多
這樣就不會由於數據傾斜導致某個reduce上落數據太多而失敗。於是原來的sql可以通過使用hint的方式指定join時使用mapjoin。
select /*+ mapjoin(A)*/ f.a,f.b from A t join B f on ( f.a=t.a and f.ftime=20110802)
再運行發現執行的效率比以前的寫法高了好多。
mapjoin還有一個很大的好處是能夠進行不等連接的join操作,如果將不等條件寫在where中,那么mapreduce過程中會進行笛卡爾積,運行效率特別低,如果使用mapjoin操作,在map的過程中就完成了不等值的join操作,效率會高很多。
例子:
select A.a ,A.b from A join B where A.a>B.a
簡單總結一下,mapjoin的使用場景:
1. 關聯操作中有一張表非常小
2.不等值的鏈接操作
MapJoin是Hive的一種優化操作,其適用於小表JOIN大表的場景,由於表的JOIN操作是在Map端且在內存進行的,所以其並不需要啟動Reduce任務也就不需要經過shuffle階段,從而能在一定程度上節省資源提高JOIN效率
簡單總結一下,mapjoin的使用場景:
1. 關聯操作中有一張表非常小
2.不等值的鏈接操作
具體使用:
方法一:
在Hive0.11前,必須使用MAPJOIN來標記顯示地啟動該優化操作,由於其需要將小表加載進內存所以要注意小表的大小
SELECT/*+ MAPJOIN(smalltable)*/.key,valueFROMsmalltableJOINbigtableONsmalltable.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, valueFROM ( select/*+MAPJOIN(smallTableOne)*/idOne, idTwo, valueFROM bigTable JOINsmallTableOneon(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