籠統的說,Hive中的Join可分為Common Join(Reduce階段完成join)和Map Join(Map階段完成join)。
一、Hive Common Join
如果不指定MapJoin或者不符合MapJoin的條件,那么Hive解析器會將Join操作轉換成Common Join,即:在Reduce階段完成join.
整個過程包含Map、Shuffle、Reduce階段。
- Map階段
讀取源表的數據,Map輸出時候以Join on條件中的列為key,如果Join有多個關聯鍵,則以這些關聯鍵的組合作為key;
Map輸出的value為join之后所關心的(select或者where中需要用到的)列;同時在value中還會包含表的Tag信息,用於標明此value對應哪個表;
按照key進行排序
- Shuffle階段
根據key的值進行hash,並將key/value按照hash值推送至不同的reduce中,這樣確保兩個表中相同的key位於同一個reduce中
- Reduce階段
根據key的值完成join操作,期間通過Tag來識別不同表中的數據。
二、Hive Map Join
1,什么是MapJoin?
MapJoin顧名思義,就是在Map階段進行表之間的連接。而不需要進入到Reduce階段才進行連接。這樣就節省了在Shuffle階段時要進行的大量數據傳輸。從而起到了優化作業的作用。
2,MapJoin的原理:
通常情況下,要連接的各個表里面的數據會分布在不同的Map中進行處理。即同一個Key對應的Value可能存在不同的Map中。這樣就必須等到Reduce中去連接。
要使MapJoin能夠順利進行,那就必須滿足這樣的條件:除了一份表的數據分布在不同的Map中外,其他連接的表的數據必須在每個Map中有完整的拷貝。
3,MapJoin適用的場景:
通過上面分析你會發現,並不是所有的場景都適合用MapJoin. 它通常會用在如下的一些情景:在二個要連接的表中,有一個很大,有一個很小,這個小表可以存放在內存中而不影響性能。
這樣我們就把小表文件復制到每一個Map任務的本地,再讓Map把文件讀到內存中待用。
4,MapJoin的實現方法:
5,Hive內置提供的優化機制之一就包括MapJoin。
三、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.不等值的鏈接操作
