4、大表join小表優化
和join相關的優化主要分為mapjoin可以解決的優化(即大表join小表)和mapjoin無法解決的優化(即大表join大表),前者相對容易解決,后者較難,比較麻煩。
首先介紹大表join小表優化。以銷售明細表為例來說明大表join小表的場景。
假如供應商進行評級,比如(五星、四星、三星、二星、一星),此時因為人員希望能夠分析各供應商星級的每天銷售情況及其占比。
開發人員一般會寫出如下SQL:
select seller_star, count(order_id) as order_cnt
from
(select order_id,seller_id from sales_detail_table where partition_value='20181010' ) a
left outer join
( select seller_id, seller_start from dim_seller where partition_value =''20181010' ) b
on a.seller_id = b.seller_id
group by b.seller_star;
現實世界的二八准則將導致訂單集中在部分供應商上,而好的供應商的評級通常會更高,此時更加加劇了數據傾斜的程度,如果不加以優化,上面SQL將會耗費很長時間,,甚至運行不出結果。
通常來說,供應商是有限的,比如上千家,上萬家,數量不會很大,而銷售明細表比較大,這就是典型的大表join小表的問題,可以通過mapjoin的方式來優化,只需要添加mapjoin hint即可,
優化后的SQL如下:
select /*+mapjoin(b)*/
seller_star, count(order_id) as order_cnt
from
(select order_id,seller_id from sales_detail_table where partition_value='20181010' ) a
left outer join
( select seller_id, seller_start from dim_seller where partition_value =''20181010' ) b
on a.seller_id = b.seller_id
group by b.seller_star;
/*+mapjoin(b)*/ 即是mapjoin hint,如果需要多個mapjoin多個表,則格式為:/*+mapjoin(b,c,d)*/.。 Hive對於mapjoin是默認開啟的,設置參數為:
Set hive.auto.convert.join = true;
mapjoin優化是在Map階段進行join,而不是通常那樣在Reduce階段按照join列進行分發后在每個Reduce節點上進行join,不需要分發也就沒有傾斜的問題,相反,Hive會將小表
全量復制到每個Map任務節點(對於本例是dim_seller表,當然進全量復制b表 sql指定的列),然后每個Map任務節點執行lookup小表即可。
從上面的分析可以看出,小表不能太大,否則全量復制分發得不償失,實際上Hive根據參數hive.mapjoin.smalltable.size(0.11.0版本后是hive.auto.convert.join.nonconditionaltask.size) 來確定小表的
大小是否滿足條件(默認25MB),實際中此參數允許的最大值可以修改,但是一般最大不能超過1GB(太大的話Map任務所在的節點內存會撐爆,Hive會報錯。另外需要注意的是,HDFS顯示的文件
大小是壓縮后的大小,當實際加載到內存的時候,容量會增大很多,很多場景下會膨脹10倍)。
參考資料:《離線和實時大數據開發實戰》