閱讀175 返回首頁    go 阿裏雲 go 技術社區[雲棲]


分區剪裁合理性評估

1.背景及目的

  MaxCompute的分區表是指在創建表時指定分區空間,即指定表內的某幾個字段作為分區列。在使用數據時,如果指定了需要訪問的分區名稱,則隻會讀取相應的分區,避免全表掃描,提高處理效率,降低費用。
  分區剪裁是指對分區列指定過濾條件,使得SQL執行時隻用讀取表的部分分區數據,避免全表掃描引起的數據錯誤及資源浪費。看起來非常簡單,但是實際情況卻常常出人意料,經常會出現分區失效的情況,先看看下麵這個例子。
  測試表test_part_cut的分區image
執行以下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截圖:
image

  從上圖可以看出該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();

image
  看上圖的紅色框的內容,表示讀取了表xxxxx_trd_slr_ord_1d的1344個分區,即該表的所有分區。

(2) 分區剪裁生效的效果

explain
select  seller_id
from    xxxxx_trd_slr_ord_1d
where   ds='20150801';

image
  看上圖紅色框的內容,表示隻讀取了表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))

image
可以看出上麵的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'
; 

image
  從上圖可以看出兩張表都走了分區剪裁。
• 分區剪裁條件均放在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'; 

image
從上圖可以看出主表的分區剪裁有效果,而從表則是進行了全表 掃描。
  (2) Right Outer Join  與Left Outer Join類似,分區剪裁條件如果放在on中則兩張表都會生效,如果放在where中,則隻有Right Outer Join右側的主表會生效,不再舉例。
  (3) Full Outer Join  分區剪裁條件隻有都放在on中才會生效,放在where中則都不會生效。

3.影響及思考

  1. 分區剪裁如果失效會影響比較大,且用戶不容易發現。因此,分區剪裁失效最好在代碼提交的時候發現比較合適。  
  2. 對於用戶自定義函數不能用於分區剪裁的問題,需要平台再深入思考解決方法。

最後更新:2017-07-18 11:03:28

  上一篇:go  【重磅推薦】MySQL大表優化方案(最全麵)
  下一篇:go  願你的大數據能有點柴米油鹽的味道.........