HIVE中join連接全解析

續寫:SQL ON Hadoop-Hive(二)-DDL數據定義語言

1.多表join

select * from table1 t1 join table2 t2 on t1.id=t2.id join table3 t3 
on t1.id=t3.id    --第一個作業的輸出與表3的連接操作
--目前hive只支持等值join,不支持非等值的連接(很難轉化成map/reduce任務)可以join多於兩個表,執行流程分析

--如果join多個表時,join key是同一個,則join會被轉化爲單個map/reduce任務,reducer端會緩存a表和b表的記錄,然後每取得一次c表記錄就計算一次join結果
select a.val,b.val,c.val from a join b on (a.key=b.key1) join c on (c.key=b.key1)

--如果join key非同一個,則join會被轉化爲多個map/reduce任務
select a.val,b.val,c.val from a join b on (a.key=b.key1) join c on (c.key=b.key2)
--join被轉化爲2個map/reduce任務.因爲b.key1用於第一次join條件,b.key2用於第二次join,第一次緩存a表用b表序列化,第二次緩存第一次map/reducer任務結果,然後用c表序列化

2.join時每次map/reducer的任務邏輯

reducer會緩存join序列中除最後一個表所有表的記錄,再通過最後一個表將結果序列化到文件系統(有助於在reducer端減少內存使用量,實踐中應該把最大那個表放在最後)

3.左半連接

hive特有語法,返回左表記錄,前提是左表記錄對於右邊表滿足on語句中的判定條件,被用來代替標準SQL中exists\in的操作(右表字段只能出現在on子句中,不能出現在select和where子句中引用,沒有right semi join)

其實內連接也可以實現同樣目的,但前者更高效(對於左表中的一條指定記錄,在右表中一旦找到匹配記錄,hive就停止掃描)

select t1.id from table_name t1 left semi join table_name2 t2 on t1.id=t2.id

4.join發生在where子句之前(以left/right outer join爲例)

select a.val,b.val from a left outer join b on (a.key=b.key) where a.ds='2016-12-30' and b.ds='2016-12-30'
問題描述:如果b找不到對應a表的記錄,所有列都會列出null包括ds列.也就是說join會過濾掉b表中不能找到匹配a表join key的所有記錄,導致LEFT OUTER與where子句無關(是將left outer join後的結果進行where條件篩選)

解決方案:在left out時使用條件
select a.val,b.val from a left outer join b on (a.key=b.key and b.ds='2016-12-29' and a.ds='2016-12-29')
說明1:這一查詢結果是預先在join階段過濾的,所以不會存在上述的問題.這一邏輯可以用於right 和full類型join中
說明2:過濾條件寫在on上面會讓基表所有數據都能顯示,不滿足條件的右表以null填充,當過濾條件寫在where上只會讓符合篩選條件的數據顯示
--hive實例
select r.phone_num,r.lab1,s.phone_num,s.lab1 from  hkdw_dk_edu r left outer join hkdw_dk_edu s on (r.phone_num=s.phone_num and s.lab1='dk_seyy' and r.lab1='dk_sryyss') where r.lab1='dk_sryyss' and s.phone_num is null

5.內連接+全連接

--如果單獨用join,如select ... from table_name1 a join table_name2 b on a.id=b.id表示內連接,full outer join全連接

6.map side join

如果在連接的表中有一張是小表,在map階段完全可以將小表讀到內存中,直接在map端進行join,這種操作可以明顯降低join所耗費的時間

select /*+MAPJOIN(t1)*/ t1.id,t2.id from table1 t1 join table2 t2 on t1.id=t2.id
--如果想讓hive自動開啓這個優化,設置hive.auto.convert.join=true(這樣hive會在必要時自動執行map端join,自動獲取兩張表的數據,判定哪張是小表放到內存中)

--自動轉換爲mapjoin
set hive.auto.convert.join = true;
--小表的最小文件大小,默認值爲25Mb
set hive.mapjoin.smalltable.filesize = 25000000;
--是否將多個mapjoin合併爲一個
set hive.auto.convert.join.noconditionaltask = true;
--多個mapjoin轉換爲1個時,所有小表的文件大小總和的最大值。
set hive.auto.convert.join.noconditionaltask.size = 10000000;

7.hive的三種join方式

1.reduce join在hive中也稱common join或shuffle join。適合兩邊數據量都較大的join,它會把相同key的value合在一起(相同的key被拖拽到同一個reducer),然後再去組合(在reduce端完成join)

set mapreduce.map.memory.mb=2049;
set mapreduce.reduce.memory.mb=20495;
set hive.auto.convert.join=false;

2.map join

參考第六點,適合一張表的數據量很大另外一張表很少(通常<=1000行)的join,那麼可將數據量少的表放到內存中,在map端做join,省去reduce運行效率會高很多

不等值join:例如a.x<b.y或者a.x like b.y等,不等值join操作hive語法解析會直接拋出錯誤。但是將不等於寫到where中會造成笛卡爾積,而且hive的where條件本身是在map階段進行的操作,所以where中寫入不等值比對不會造成額外負擔

select /*+ MAPJOIN(a) */
a.start_level, b.*
from dim_level a inner
join (select * from test) b
where b.xx>=a.start_level and b.xx<end_level;

3.SMB( sort merge buket) join

使用場景:大表對大表。在運行SMS join時會重新創建兩張表(後臺默認做的,不需要用戶主動創建)

set hive.auto.convert.sortmerge.join=true
set hive.optimize.bucketmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge=true;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章