1. 程式人生 > 其它 >一條delete語句的調優(r4筆記第86天)

一條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個分割槽的刪除可以簡化到有一個特定的分割槽,效能調優在這個時候就是一個接力棒式的工作。問題經過一步一步的分析和確認,也變得清晰起來。