當您對一個大表和一個或多個小表執行join
操作時,可以在select
語句中顯式指定mapjoin
Hint提示以提升查詢效能。本文為您介紹如何通過mapjoin hint
串連表。
功能介紹
整個JOIN過程包含Map、Shuffle和Reduce三個階段。通常情況下,join
操作在Reduce階段執行表串連。
mapjoin
在Map階段執行表串連,而非等到Reduce階段才執行表串連,可以縮短大量資料轉送時間,提升系統資源使用率,從而起到最佳化作業的作用。
在對大表和一個或多個小表執行join
操作時,mapjoin
會將您指定的小表全部載入到執行join
操作的程式的記憶體中,在Map階段完成表串連從而加快join
的執行速度。
此外,MaxCompute SQL不支援在普通join
的on
條件中使用不等值運算式、or
等邏輯複雜的join
條件,但是在mapjoin
中可以進行上述操作。
使用限制
mapjoin
操作的使用限制如下:
mapjoin
在Map階段會將指定表的資料全部載入在記憶體中,因此指定的表僅能為小表,且表被載入到記憶體後佔用的總記憶體不得超過512 MB。由於MaxCompute是壓縮儲存,因此小表在被載入到記憶體後,資料大小會急劇膨脹。此處的512 MB是指載入到記憶體後的空間大小。mapjoin
中join
操作的限制如下:left outer join
的左表必須是大表。right outer join
的右表必須是大表。不支援
full outer join
。inner join
的左表或右表均可以是大表。
mapjoin
最多支援指定128張小表,否則報語法錯誤。
使用方法
您需要在select
語句中使用Hint提示/*+ mapjoin(<table_name>) */
才會執行mapjoin
。需要注意的是:
引用小表或子查詢時,需要引用別名。
mapjoin
支援小表為子查詢。在
mapjoin
中,可以使用不等值串連或or
串連多個條件。您可以通過不寫on
語句而通過mapjoin on 1 = 1
的形式,實現笛卡爾乘積的計算。例如select /*+ mapjoin(a) */ a.id from shop a join table_name b on 1=1;
,但此操作可能帶來資料量膨脹問題。mapjoin
中多個小表用英文逗號(,)分隔,例如/*+ mapjoin(a,b,c)*/
。
部分子查詢(例如SCALAR、IN、NOT IN、EXISTS或NOT EXISTS)在執行過程中會被轉換成JOIN進行計算,MAPJOIN是一種高效的JOIN演算法,若您確定SUBQUERY的計算結果為小表,可以在子查詢SUBQUERY語句中使用HINT來顯式地指定使用MAPJOIN演算法。詳情請參見SUBQUERY_MAPJOIN HINT。
樣本資料
為便於理解,本文為您提供來源資料,基於來源資料提供相關樣本。建立表sale_detail和sale_detail_sj,並添加資料,命令樣本如下:
--建立一張分區表sale_detail。
create table if not exists sale_detail
(
shop_name string,
customer_id string,
total_price double
)
partitioned by (sale_date string, region string);
create table if not exists sale_detail_sj
(
shop_name string,
customer_id string,
total_price double
)
partitioned by (sale_date string, region string);
--向源表增加分區。
alter table sale_detail add partition (sale_date='2013', region='china');
alter table sale_detail_sj add partition (sale_date='2013', region='china');
--向源表追加資料。
insert into sale_detail partition (sale_date='2013', region='china') values ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
insert into sale_detail_sj partition (sale_date='2013', region='china') values ('s1','c1',100.1),('s2','c2',100.2),('s5','c2',100.2),('s2','c2',100.2);
使用樣本
對錶sale_detail和sale_detail_sj執行join
操作,滿足sale_detail_sj中的total_price小於sale_detail中的total_price,或sale_detail_sj中的total_price與sale_detail中的total_price之和小於500的條件,命令樣本如下:
--允許分區表的全表掃描
SET odps.sql.allow.fullscan=true;
-- 使用mapjoin查詢
select /*+ mapjoin(a) */
a.shop_name,
a.total_price,
b.total_price
from sale_detail_sj a join sale_detail b
on a.total_price < b.total_price or a.total_price + b.total_price < 500;
返回結果如下:
+-----------+-------------+--------------+
| shop_name | total_price | total_price2 |
+-----------+-------------+--------------+
| s1 | 100.1 | 100.1 |
| s2 | 100.2 | 100.1 |
| s5 | 100.2 | 100.1 |
| s2 | 100.2 | 100.1 |
| s1 | 100.1 | 100.2 |
| s2 | 100.2 | 100.2 |
| s5 | 100.2 | 100.2 |
| s2 | 100.2 | 100.2 |
| s1 | 100.1 | 100.3 |
| s2 | 100.2 | 100.3 |
| s5 | 100.2 | 100.3 |
| s2 | 100.2 | 100.3 |
+-----------+-------------+--------------+