一條delete語句的調優(r4筆記第86天)
今天剛上上班,就接到客戶的郵件,說生產環境中執行某一條delete sql語句的時間超過了3個小時。最後客戶無奈取消了這次資料清理,準備今天在申請時間重做。所以希望我在下午之前能夠調優一下sql語句。 我拿到sql語句。是一個簡單的delete語句,這個表是一個分割槽表,表中的資料大約有6億條,要刪除的資料大概有900多萬條。
delete event
where cycle_code = 25
and cycle_month = 2
and cycle_year = 2015
and customer_id = 5289835;
Plan hash value: 2439880320 ----------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ----------------------------------------------------------------------------------------------------------------------- | 0 | DELETE STATEMENT | | 3238K| 135M| 404K (1)| 01:20:52 | | | | 1 | DELETE | EVENT | | | | | | | | 2 | PARTITION RANGE ITERATOR | | 3238K| 135M| 404K (1)| 01:20:52 | 241 | 261 | |* 3 | TABLE ACCESS BY LOCAL INDEX ROWID| EVENT | 3238K| 135M| 404K (1)| 01:20:52 | 241 | 261 | |* 4 | INDEX RANGE SCAN | EVENT_1UQ | 1370K| | 40255 (1)| 00:08:04 | 241 | 261 | -----------------------------------------------------------------------------------------------------------------------
發現走了索引掃描,看起來效能也不會差到哪去啊? 從整體來看,從6億條記錄中刪除900多萬條資料,走索引掃描感覺感覺確實是不錯的選擇。 首先查看了表的分割槽規則和基本的資料分佈情況, 分割槽規則是基於cycle_code,cycle_month,sub_partition_id這三個欄位,從查詢條件來看,cycle_code,cycle_month剛好就是分割槽欄位。
TABLE_NAME PARTITION PARTITION_COUNT COLUMN_LIST PART_COUNTS SUBPAR_COUNT STATUS -------------------- --------- --------------- ------------------------------ ----------- ------------ ------ EVENT RANGE 721 CYCLE_CODE,CYCLE_MONTH,SUB_PAR TITION_ID 3 0 VALID
資料分佈的情況如下,根據分割槽邏輯,資料只可能在這20個分割槽中。
partition_name high_value tablespace_name num_rows
C25_M2_S1 25, 2, 5 DATAH01 84246910
C25_M2_S2 25, 2, 10 DATAH01 3427570
C25_M2_S3 25, 2, 15 DATAH01 3523431
C25_M2_S4 25, 2, 20 DATAH01 3988140
C25_M2_S5 25, 2, 25 DATAH01 2700687
C25_M2_S6 25, 2, 30 DATAH01 2477792
C25_M2_S7 25, 2, 35 DATAH01 2490349
C25_M2_S8 25, 2, 40 DATAH01 11755212
C25_M2_S9 25, 2, 45 DATAH01 3184953
C25_M2_S10 25, 2, 50 DATAH01 2656802
C25_M2_S11 25, 2, 55 DATAH01 4434668
C25_M2_S12 25, 2, 60 DATAH01 2776079
C25_M2_S13 25, 2, 65 DATAH01 2949885
C25_M2_S14 25, 2, 70 DATAH01 2837790
C25_M2_S15 25, 2, 75 DATAH01 6285172
C25_M2_S16 25, 2, 80 DATAH01 2743439
C25_M2_S17 25, 2, 85 DATAH01 3574228
C25_M2_S18 25, 2, 90 DATAH01 3600820
C25_M2_S19 25, 2, 95 DATAH01 7415434
C25_M2_S20 25, 2, 100 DATAH01 3446285
有了這些資訊,發現收穫還是不小的,我寫了一個指令碼,來嵌入customer_id這個欄位,來檢視每個分割槽中需要刪除的資料情況,結果發現第一個分割槽有8千多萬條資料,查詢的時間很長,最後竟然沒有資料可以刪除,其它的分割槽測試的時候執行速度都很快。 分割槽C25_M2_S8中的要刪除的資料有9百多萬,其它分割槽都沒有匹配的資料,從資料層面,我是沒法確定這些分割槽一定沒有可能插入新資料的。 所以分析了上面的情況,我對分割槽C25_M2_S1做了特殊處理,按照執行計劃是走索引掃描的,因為查詢條件的範圍有點大,還沒有匹配的資料,所以我嘗試走全表掃描,開啟了並行,經過測試,發現速度還是很快的,基本在1分鐘左右就能夠很快過濾出資料來。 所以從資料層面我提供的語句如下,把最大的分割槽放在了最後處理。
set linesize 200
set timing on
set time on
alter session force parallel dml parallel 16;
delete event partition(C25_M2_S2) where cycle_code=25 and cycle_month=2 and cycle_year=2015 and customer_id=5289835;
commit;
delete event partition(C25_M2_S3) where cycle_code=25 and cycle_month=2 and cycle_year=2015 and customer_id=5289835;
commit;
delete event partition(C25_M2_S4) where cycle_code=25 and cycle_month=2 and cycle_year=2015 and customer_id=5289835;
commit;
。。。。。。。
delete event partition(C25_M2_S20) where cycle_code=25 and cycle_month=2 and cycle_year=2015 and customer_id=5289835;
commit;
delete /*+ full(rated_event) parallel(rated_event,16) */ event partition(C25_M2_S1) where cycle_code=25 and cycle_month=2 and cycle_year=2015 and customer_id=5289835;
commit;
事情到此一般就結束了,開發找到我,我們做了進一步的溝通,她根據我提供的指令碼提出了一些問題,她從業務層面來做了確認,說資料只會在C25_M2_S8這個分割槽上,有了業務確認,調優的語句就更加簡化了。
set linesize 200
set timing on
set time on
alter session force parallel dml parallel 16;
delete event partition(C25_M2_S8) where cycle_code=25 and cycle_month=2 and cycle_year=2015 and customer_id=5289835;
commit;
檢視執行計劃,合理的走了全表掃描,因為分割槽中有1千多萬的記錄,刪除900多萬的資料,走全表掃描還是情理之中的。
Plan hash value: 1742190108
----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 9115K| 382M| 19351 (1)| 00:03:53 | | | | | |
| 1 | PX COORDINATOR | | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | 9115K| 382M| 19351 (1)| 00:03:53 | | | Q1,00 | P->S | QC (RAND) |
| 3 | DELETE | EVENT | | | | | | | Q1,00 | PCWP | |
| 4 | PX BLOCK ITERATOR | | 9115K| 382M| 19351 (1)| 00:03:53 | 248 | 248 | Q1,00 | PCWC | |
|* 5 | TABLE ACCESS FULL| EVENT | 9115K| 382M| 19351 (1)| 00:03:53 | 248 | 248 | Q1,00 | PCWP | |
----------------------------------------------------------------------------------------------------------------------------------
通過這個例子,我們可以看到原本索引掃描的執行計劃看起來很好,但是執行效率卻大打折扣,在分析了分割槽表的分割槽規則和資料分佈情況之後,發現可以把原本700多個分割槽簡化到20個,加上業務層面的確認,本來20個分割槽的刪除可以簡化到有一個特定的分割槽,效能調優在這個時候就是一個接力棒式的工作。問題經過一步一步的分析和確認,也變得清晰起來。