續寫: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;