分區剪裁合理性評估
1.背景及目的
MaxCompute的分區表是指在創建表時指定分區空間,即指定表內的某幾個字段作為分區列。在使用數據時,如果指定了需要訪問的分區名稱,則隻會讀取相應的分區,避免全表掃描,提高處理效率,降低費用。
分區剪裁是指對分區列指定過濾條件,使得SQL執行時隻用讀取表的部分分區數據,避免全表掃描引起的數據錯誤及資源浪費。看起來非常簡單,但是實際情況卻常常出人意料,經常會出現分區失效的情況,先看看下麵這個例子。
測試表test_part_cut的分區
執行以下SQL代碼:
select count(*)
from test_part_cut
where ds= bi_week_dim('20150102');
其中為bi_week_dim自定義函數:返回格式為 (年,第幾周)
如果是正常日期,判斷日期是所傳入參數中年份所屬
周,以周四為一周的起始日期,如果碰到20140101因為屬於
周三所以算在2013年最後一周返回2013,52
而20150101則返回是2015,1
如果是類似20151231是周四又恰逢與20160101在同一周
則返回2016,1
bi_week_dim('20150102')的返回結果是2015,1,不符合表test_part_cut的分區值,通常我們會認為上麵的SQL不會讀任何分區,而實際情況卻是該SQL讀了表test_part_cut的所有分區,看一下LogView截圖:
從上圖可以看出該SQL在執行的時候讀取了表test_part_cut的所有分區。
從上麵例子可以看出,分區剪裁使用盡管簡單,但也容易造成錯誤。因此,本文主要的目的有兩點:(1) 判斷SQL中分區剪裁是否生效。 (2) 了解常見的導致分區剪裁失效的場景。
2.方案
2.1判斷分區剪裁是否生效
通過explain命令查看SQL的執行計劃,用於發現SQL中的分區剪裁是否生效。
(1) 分區剪裁沒生效的效果
explain
select seller_id
from xxxxx_trd_slr_ord_1d
where ds=rand();
看上圖的紅色框的內容,表示讀取了表xxxxx_trd_slr_ord_1d的1344個分區,即該表的所有分區。
(2) 分區剪裁生效的效果
explain
select seller_id
from xxxxx_trd_slr_ord_1d
where ds='20150801';
看上圖紅色框的內容,表示隻讀取了表xxxxx_trd_slr_ord_1d的20150801的分區。
2.2 分區剪裁失效的場景分析
分區剪裁在使用自定義函數或者部分係統函數的時候會失效,在Join關聯時的Where條件中也有可能會失效。下麵針對這兩種場景分別舉例說明。
1. 自定義函數導致分區剪裁失效 當分區剪裁的條件中使用了用戶自定義函數,則分區剪裁會失效,即使是使用係統函數也可能會導致分區剪裁失效。所以,對於分區值的限定,如果使用了非常規函數需要用explain命令通過查看執行計劃確定分區剪裁是否已經生效。
explain
select ...
from xxxxx_base2_brd_ind_cw
where ds = concat(SPLIT_PART(bi_week_dim(' ${bdp.system.bizdate}'), ',', 1), SPLIT_PART(bi_week_dim(' ${bdp.system.bizdate}'), ',', 2))
可以看出上麵的SQL因為分區剪裁使用了用戶自定義的函數導致全表掃描。
2. Join使用時分區剪裁失效 在SQL語句中使用Join進行關聯時,如果分區剪裁條件放在on中則分區剪裁會生效,如果放在where條件中,主表的分區剪裁會生效,從表則不會生效。下麵針對三種Join具體說明。
(1) Left Outer Join
• 分區剪裁條件均放在on中
explain
select a.seller_id
,a.pay_ord_pbt_1d_001
from xxxxx_trd_slr_ord_1d a
left outer join
xxxxx_seller b
on a.seller_id=b.user_id
and a.ds='20150801'
and b.ds='20150801'
;
從上圖可以看出兩張表都走了分區剪裁。
• 分區剪裁條件均放在where中
explain
select a.seller_id
,a.pay_ord_pbt_1d_001
from xxxxx_trd_slr_ord_1d a
left outer join
xxxxx_seller b
on a.seller_id=b.user_id
where a.ds='20150801'
and b.ds='20150801';
從上圖可以看出主表的分區剪裁有效果,而從表則是進行了全表 掃描。
(2) Right Outer Join 與Left Outer Join類似,分區剪裁條件如果放在on中則兩張表都會生效,如果放在where中,則隻有Right Outer Join右側的主表會生效,不再舉例。
(3) Full Outer Join 分區剪裁條件隻有都放在on中才會生效,放在where中則都不會生效。
3.影響及思考
- 分區剪裁如果失效會影響比較大,且用戶不容易發現。因此,分區剪裁失效最好在代碼提交的時候發現比較合適。
- 對於用戶自定義函數不能用於分區剪裁的問題,需要平台再深入思考解決方法。
最後更新:2017-07-18 11:03:28