Hive 基本語法操練(五):Hive 的 JOIN 用法


Hive 的 JOIN 用法

 hive只支持等連接,外連接,左半連接。hive不支持非相等的join條件(通過其他方式實現,如left outer join),因為它很難在map/reduce中實現這樣的條件。而且,hive可以join兩個以上的表。

1、等連接

 只有等連接才允許

hive> SELECT a.* FROM a JOIN b ON (a.id = b.id);  
hive> SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department); 

 

2、多表連接

 同個查詢,可以join兩個以上的表

hive> SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2); 

 

3、join的緩存和任務轉換

 hive轉換多表join時,如果每個表在join字句中,使用的都是同一個列,只會轉換為一個單獨的map/reduce。

hive> SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1);

 

 被轉換為兩個map/reduce任務,因為b的key1列在第一個join條件使用,而b表的key2列在第二個join條件使用。第一個map/reduce任務join a和b。第二個任務是第一個任務的結果join c。

hive> SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2); 

 

 在join的每個map/reduce階段,序列中的最后一個表,當其他被緩存時,它會流到reducers。所以,reducers需要緩存join關鍵字的特定值組成的行,通過組織最大的表出現在序列的最后,有助於減少reducers的內存。

hive> SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1);

 

 三個表,在同一個獨立的map/reduce任務做join。a和b的key對應的特定值組成的行,會緩存在reducers的內存。然后reducers接受c的每一行,和緩存的每一行做join計算。

hive> SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2); 

 

 這里有兩個map/reduce任務在join計算被調用。第一個是a和b做join,然后reducers緩存a的值,另一邊,從流接收b的值。第二個階段,reducers緩存第一個join的結果,另一邊從流接收c的值。

 在join的每個map/reduce階段,通過關鍵字,可以指定哪個表從流接收。

hive> SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1);

 

 三個表的連接,會轉換為一個map/reduce任務,reducer會把b和c的key的特定值緩存在內存里,然后從流接收a的每一行,和緩存的行做join。

4、join的結果

 LEFT,RIGHT,FULL OUTER連接存在是為了提供ON語句在沒有匹配時的更多控制。例如,這個查詢:

hive> SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key);

 

 將會返回a的每一行。如果b.key等於a.key,輸出將是a.val,b.val,如果a沒有和b.key匹配,輸出的行將是 a.val,NULL。如果b的行沒有和a.key匹配上,將被拋棄。語法"FROM a LEFT OUTER JOIN b"必須寫在一行,為了理解它如何工作——這個查詢,a是b的左邊,a的所有行會被保持;RIGHT OUTER JOIN將保持b的所有行, FULL OUTER JOIN將會保存a和b的所有行。OUTER JOIN語義應該符合標准的SQL規范。

5、join的過濾

 Joins發生在where字句前,所以,如果要限制join的輸出,需要寫在where字句,否則寫在JOIN字句。現在討論的一個混亂的大點,就是分區表

hive> SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)  WHERE a.ds='2018-05-22' AND b.ds='2018-05-22';

 

 將會連接a和b,產生a.val和b.val的列表。WHERE字句,也可以引用join的輸出列,然后過濾他們。 但是,無論何時JOIN的行找到a的key,但是找不到b的key時,b的所有列會置成NULL,包括ds列。這就是說,將過濾join輸出的所有行,包括沒有合法的b.key的行。然后你會在LEFT OUTER的要求撲空。 也就是說,如果你在WHERE字句引用b的任何列,LEFT OUTER的部分join結果是不相關的。所以,當外連接時,使用這個語句

hive> SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key AND b.ds='2018-05-22' AND a.ds='2018-05-22';

 

 join的輸出會預先過濾,然后你不用對有a.key而沒有b.key的行做過濾。RIGHT和FULL join也是一樣的邏輯。

6、join的順序

 join是不可替換的,連接是從左到右,不管是LEFT或RIGHT join。

hive>  SELECT a.val1, a.val2, b.val, c.val  FROM a  JOIN b ON (a.key = b.key)  LEFT OUTER JOIN c ON (a.key = c.key);

 

 首先,連接a和b,扔掉a和b中沒有匹配的key的行。結果表再連接c。這提供了直觀的結果,如果有一個鍵都存在於A和C,但不是B:完整行(包括 a.val1,a.val2,a.key)會在"a jOIN b"步驟,被丟棄,因為它不在b中。結果沒有a.key,所以當它和c做LEFT OUTER JOIN,c.val也無法做到,因為沒有c.key匹配a.key(因為a的行都被移除了)。類似的,RIGHT OUTER JOIN(替換為LEFT),我們最終會更怪的效果,NULL, NULL, NULL, c.val。因為盡管指定了join key是a.key=c.key,我們已經在第一個JOIN丟棄了不匹配的a的所有行。

 為了達到更直觀的效果,相反,我們應該從

hive> FROM c LEFT OUTER JOIN a ON (c.key = a.key) LEFT OUTER JOIN b ON (c.key = b.key);

 

 LEFT SEMI JOIN實現了相關的IN / EXISTS的子查詢語義的有效途徑。由於Hive目前不支持IN / EXISTS的子查詢,所以你可以用 LEFT SEMI JOIN 重寫你的子查詢語句。LEFT SEMI JOIN 的限制是, JOIN 子句中右邊的表只能在 ON 子句中設置過濾條件,在 WHERE 子句、SELECT 子句或其他地方過濾都不行。

hive> SELECT a.key, a.value FROM a WHERE a.key in (SELECT b.key FROM B); 

 

 可以重寫為

hive> SELECT a.key, a.val FROM a LEFT SEMI JOIN b on (a.key = b.key);  

7、map 端 join

 但如果所有被連接的表是小表,join可以被轉換為只有一個map任務。查詢是

hive> SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key;

 

 不需要reducer。對於每一個mapper,A和B已經被完全讀出。限制是a FULL/RIGHT OUTER JOIN b不能使用。

 如果表在join的列已經分桶了,其中一張表的桶的數量,是另一個表的桶的數量的整倍,那么兩者可以做桶的連接。如果A有4個桶,表B有4個桶,下面的連接:

hive> SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key; 

 

 只能在mapper工作。為了為A的每個mapper完整抽取B。對於上面的查詢,mapper處理A的桶1,只會抽取B的桶1,這不是默認行為,要使用以下參數:

hive> set hive.optimize.bucketmapjoin = true; 

 

 如果表在join的列經過排序,分桶,而且他們有相同數量的桶,可以使用排序-合並 join。每個mapper,相關的桶會做連接。如果A和B有4個桶

hive> SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM A a join B b on a.key = b.key; 

 

 只能在mapper使用。使用A的桶的mapper,也會遍歷B相關的桶。這個不是默認行為,需要配置以下參數:

hive> set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;  
hive> set hive.optimize.bucketmapjoin = true;  
hive> set hive.optimize.bucketmapjoin.sortedmerge = true;  

 



以上就是博主為大家介紹的這一板塊的主要內容,這都是博主自己的學習過程,希望能給大家帶來一定的指導作用,有用的還望大家點個支持,如果對你沒用也望包涵,有錯誤煩請指出。如有期待可關注博主以第一時間獲取更新哦,謝謝! 

 
        

 版權聲明:本文為博主原創文章,未經博主允許不得轉載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM