1.Common/Shuffle/Reduce Join
Reduce Join在Hive中也叫Common Join或Shuffle Join
如果兩邊數據量都很大,它會進行把相同key的value合在一起,正好符合我們在sql中的join,然后再去組合,如圖所示。
2.Map Join
- 1) 大小表連接:
- 如果一張表的數據很大,另外一張表很少(<1000行),那么我們可以將數據量少的那張表放到內存里面,在map端做join。
- Hive支持Map Join,用法如下
-
select /*+ MAPJOIN(time_dim) */ count(1) from store_sales join time_dim on (ss_sold_time_sk = t_time_sk)
2) 需要做不等值join操作(a.x < b.y 或者 a.x like b.y等)
-
這種操作如果直接使用join的話語法不支持不等於操作,hive語法解析會直接拋出錯誤
如果把不等於寫到where里會造成笛卡爾積,數據異常增大,速度會很慢。甚至會任務無法跑成功~
根據mapjoin的計算原理,MapJoin會把小表全部讀入內存中,在map階段直接拿另外一個表的數據和內存中表數據做匹配。這種情況下即使笛卡爾積也不會對任務運行速度造成太大的效率影響。
而且hive的where條件本身就是在map階段進行的操作,所以在where里寫入不等值比對的話,也不會造成額外負擔。
select /*+ MAPJOIN(a) */ a.start_level, b.* from dim_level a join (select * from test) b where b.xx>=a.start_level and b.xx<end_level;
3) MAPJOIN 結合 UNIONALL
原始sql:select a.*,coalesce(c.categoryid,’NA’) as app_category from (select * from t_aa_pvid_ctr_hour_js_mes1 ) a left outer join (select * fromt_qd_cmfu_book_info_mes ) c on a.app_id=c.book_id;
速度很慢,老辦法,先查下數據分布:
select * from (selectapp_id,count(1) cnt fromt_aa_pvid_ctr_hour_js_mes1 group by app_id) t order by cnt DESC limit 50;
數據分布如下:
NA 617370129 2 118293314 1 40673814 d 20151236 b 1846306 s 1124246 5 675240 8 642231 6 611104 t 596973 4 579473 3 489516 7 475999 9 373395 107580 10508
我們可以看到除了NA是有問題的異常值,還有appid=1~9的數據也很多,而這些數據是可以關聯到的,所以這里不能簡單的隨機函數了。而t_qd_cmfu_book_info_mes這張app庫表,又有幾百萬數據,太大以致不能放入內存使用mapjoin。
解決方:首先將appid=NA和1到9的數據存入一組,並使用mapjoin與維表(維表也限定appid=1~9,這樣內存就放得下了)關聯,而除此之外的數據存入另一組,使用普通的join,最后使用union all 放到一起。
select a.*,coalesce(c.categoryid,’NA’) as app_category from --if app_id is not number value or <=9,then not join (select * from t_aa_pvid_ctr_hour_js_mes1 where cast(app_id as int)>9 ) a left outer join (select * from t_qd_cmfu_book_info_mes where cast(book_id as int)>9) c on a.app_id=c.book_id union all select /*+ MAPJOIN(c)*/ a.*,coalesce(c.categoryid,’NA’) as app_category from --if app_id<=9,use map join (select * from t_aa_pvid_ctr_hour_js_mes1 where coalesce(cast(app_id as int),-999)<=9) a left outer join (select * fromt_qd_cmfu_book_info_mes where cast(book_id as int)<=9) c --if app_id is not number value,then not join on a.app_id=c.book_id;
- 設置:
-
當然也可以讓hive自動識別,把join變成合適的Map Join如下所示
注:當設置為true的時候,hive會自動獲取兩張表的數據,判定哪個是小表,然后放在內存中
set hive.auto.convert.join=true; select count(*) from store_sales join time_dim on (ss_sold_time_sk = t_time_sk)
3.SMB(Sort-Merge-Buket) Join
- 場景:
-
大表對小表應該使用MapJoin,但是如果是大表對大表,如果進行shuffle,那就要人命了啊,第一個慢不用說,第二個容易出異常,既然是兩個表進行join,肯定有相同的字段吧。
-
tb_a - 5億(按排序分成五份,每份1億放在指定的數值范圍內,類似於分區表)
a_id
100001 ~ 110000 - bucket-01-a -1億
110001 ~ 120000
120001 ~ 130000
130001 ~ 140000
140001 ~ 150000 -
tb_b - 5億(同上,同一個桶只能和對應的桶內數據做join)
b_id
100001 ~ 110000 - bucket-01-b -1億
110001 ~ 120000
120001 ~ 130000
130001 ~ 140000
140001 ~ 150000 -
注:實際生產環境中,一天的數據可能有50G(舉例子可以把數據弄大點,比如說10億分成1000個bucket)。
- 原理:
-
在運行SMB Join的時候會重新創建兩張表,當然這是在后台默認做的,不需要用戶主動去創建,如下所示:
-
設置(默認是false):
set hive.auto.convert.sortmerge.join=true set hive.optimize.bucketmapjoin=true; set hive.optimize.bucketmapjoin.sortedmerge=true;
hive中 bucket mapjoin 與 SMB join(Sort-Merge-Bucket)區別:
1 bucket mapjoin
1.1 條件
1) set hive.optimize.bucketmapjoin = true;
2) 一個表的bucket數是另一個表bucket數的整數倍
3) bucket列 == join列
4) 必須是應用在map join的場景中1.2 注意
1)如果表不是bucket的,只是做普通join。
2 SMB join (針對bucket mapjoin 的一種優化)
2.1 條件
1)
set hive.auto.convert.sortmerge.join=true;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.auto.convert.sortmerge.join.noconditionaltask=true;
2) 小表的bucket數=大表bucket數
3) Bucket 列 == Join 列 == sort 列
4) 必須是應用在bucket mapjoin 的場景中2.2 注意
hive並不檢查兩個join的表是否已經做好bucket且sorted,需要用戶自己去保證join的表,否則可能數據不正確。有兩個辦法
1)hive.enforce.sorting 設置為true。
2)手動生成符合條件的數據,通過在sql中用distributed c1 sort by c1 或者 cluster by c1
表創建時必須是CLUSTERED且SORTED,如下
create table test_smb_2(mid string,age_id string)
CLUSTERED BY(mid) SORTED BY(mid) INTO 500 BUCKETS; -