Hive 中的 LEFT SEMI JOIN 與 JOIN ON 的前世此生

hive 的 join 類型有好幾種,其實都是把 MR 中的幾種方式都封裝實現了,其中 join on、left semi join 算是裏邊具備表明性,且使用頻率較高的 join 方式。 html

一、聯繫

他們都是 hive join 方式的一種,join on 屬於 common join(shuffle join/reduce join),而 left semi join 則屬於 map join(broadcast join)的一種變體,從名字能夠看出他們的實現原理有差別。 sql

二、區別

(1)Semi Join,也叫半鏈接,是從分佈式數據庫中借鑑過來的方法。它的產生動機是:對於reduce side join,跨機器的數據傳輸量很是大,這成了join操做的一個瓶頸,若是可以在map端過濾掉不會參加join操做的數據,則能夠大大節省網絡IO,提高執行效率。
實現方法很簡單:選取一個小表,假設是File1,將其參與join的key抽取出來,保存到文件File3中,File3文件通常很小,能夠放到內存中。在map階段,使用DistributedCache將File3複製到各個TaskTracker上,而後將File2中不在File3中的key對應的記錄過濾掉,剩下的reduce階段的工做與reduce side join相同。
因爲
hive 中沒有 in/exist 這樣的子句(新版將支持),因此須要將這種類型的子句轉成 left semi join。left semi join 是隻傳遞表的 join key 給 map 階段 , 若是 key 足夠小仍是執行 map join, 若是不是則仍是 common join。關於 common join(shuffle join/reduce join)的原理請參考文末 refer。 數據庫

(2)left semi join 子句中右邊的表只能在 ON 子句中設置過濾條件,在 WHERE 子句、SELECT 子句或其餘地方過濾都不行。 網絡

(3)對待右表中重複key的處理方式差別:由於 left semi join 是 in(keySet) 的關係,遇到右表重複記錄,左表會跳過,而 join on 則會一直遍歷。 分佈式

最後的結果是這會形成性能,以及 join 結果上的差別。 ide

(4)left semi join 中最後 select 的結果只許出現左表,由於右表只有 join key 參與關聯計算了,而 join on 默認是整個關係模型都參與計算了。 oop

三、兩種 join 的「坑」

  因爲HIVE中都是等值鏈接,在JOIN使用的時候,有兩種寫法在理論上是能夠達到相同的效果的,可是因爲實際狀況的不同,子表中數據的差別致使結果也不太同樣。  性能

寫法一: left semi join

select
           a.bucket_id,
        a.search_type,
            a.level1,
        a.name1,
        a.level2,
        a.name2,
        cast((a.alipay_fee) as double) as zhuliu_alipay,
        cast(0 as double) as total_alipay
        from tmall_data_fdi_search_zhuliu_alipay_cocerage_bucket_1 a
     left semi join
     tmall_data_fdi_dim_main_auc b
     on (a.level2 = b.cat_id2
         and a.brand_id = b.brand_id
       and b.cat_id2 > 0
         and b.brand_id > 0
         and b.max_price = 0
     )

結果是 3121 條 學習

寫法二: join on

select
           a.bucket_id,
        a.search_type,
            a.level1,
        a.name1,
        a.level2,
        a.name2,
        cast((a.alipay_fee) as double) as zhuliu_alipay,
        cast(0 as double) as total_alipay
        from tmall_data_fdi_search_zhuliu_alipay_cocerage_bucket_1 a
     join   tmall_data_fdi_dim_main_auc b
     on (a.level2 = b.cat_id2
         and a.brand_id = b.brand_id)
  where  b.cat_id2 > 0
         and b.brand_id > 0
         and b.max_price = 0

結果是 3142 條 spa

這兩種寫法帶來的值竟然不是相等的,我一直覺得理解這兩種方式的寫法是同樣的, 可是統計的結果倒是不同的。 
通過一層一層的查找,發現是因爲子表(tmall_data_fdi_dim_main_auc)中存在重複的數據,當使用JOIN ON的時候,A,B表會關聯出兩條記錄,應爲ON上的條件符合; 
而是用LEFT SEMI JOIN 當A表中的記錄,在B表上產生符合條件以後就返回,不會再繼續查找B表記錄了,因此若是B表有重複,也不會產生重複的多條記錄。 

大多數狀況下 JOIN ON 和 left semi on 是對等的,可是在上述狀況下會出現重複記錄,致使結果差別,因此你們在使用的時候最好能瞭解這兩種方式的原理,避免掉「坑」。


四、Refer

(1)HIVE 中內鏈接(JOIN ON)與LEFT SEMI JOIN查詢結果不一致的分析

http://scholers.iteye.com/blog/1710594

(2)Hadoop 中的兩表join

http://www.gemini5201314.net/hadoop/hadoop-%E4%B8%AD%E7%9A%84%E4%B8%A4%E8%A1%A8join.html

(3)What is difference between natural join and semi join?

http://wiki.answers.com/Q/What_is_difference_between_natural_join_and_semi_join#q151543010/page/2

(4)MapReduce 中的兩表 join 幾種方案簡介

http://my.oschina.net/leejun2005/blog/95186

(5)幾種 hive join 類型簡介

http://my.oschina.net/leejun2005/blog/82523

(6)Hive & Performance 學習筆記

http://my.oschina.net/leejun2005/blog/158491#OSC_h3_8

相關文章
相關標籤/搜索