一條全表掃描sql語句的分析

dbhelper發表於2015-02-24
今天在對生產系統做監控的時候,發現一個process的cpu消耗很高,抓取了對應的session和執行的sql語句。
發現是一個簡單的update語句,這樣一條如果CPU消耗較大,很可能是由於全表掃描的。
UPDATE
COMM_ACTIVITY SET COMM_ACTIVITY.EXTRACT_STATUS = NVL(:1 ,
EXTRACT_STATUS), COMM_ACTIVITY.SOURCE_TYPE = NVL(:2 , SOURCE_TYPE),
OPERATOR_ID = :3 , APPLICATION_ID = :4 , DL_SERVICE_CODE = :5 ,
DL_UPDATE_STAMP = :6 , SYS_UPDATE_DATE = SYSDATE where
COMM_ACTIVITY.ACTIVITY_CODE=:7  AND
COMM_ACTIVITY.EXTRACT_STATUS=:8

檢視了對應的sql執行計劃,發現和預期是一致的。
Plan hash value: 557276772
----------------------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |                   |       |       | 11187 (100)|          |
|   1 |  UPDATE            |     COMM_ACTIVITY |       |       |            |          |
|*  2 |   TABLE ACCESS FULL|     COMM_ACTIVITY |   370K|    13M| 11187   (1)| 00:02:15 |
----------------------------------------------------------------------------------------
對這樣的一條語句,該怎麼判定呢?
首先走全表掃描是否合理,這個可以從表的資料量來判定,如果表中資料很多,全表掃描肯定是很不划算的,如果就幾十幾百條資料,走全表掃描應該沒有什麼影響。這個表中的資料在百萬以上,所以走全表掃描還是需要分析原因的。
其次需要檢視對應的索引資訊,如果存在對應的索引資訊而不走索引,那麼就很可能是由於資料型別衝突導致的。具體的案例可以參見:http://blog.itpub.net/23718752/viewspace-1142678/
    如果不存在對應的索引,那麼需要考慮這種執行的結果是否可接受,這個判定的一個標準就是執行的頻率,如果某個語句執行頻率很高,走了全表掃描,資源消耗大,就很可能是需要改進的。
    如果某個語句走了全表掃描,但是執行頻率很低,幾天,一個星期左右執行一次,那麼這樣的影響相對就小很多,執行的情況也是基本可以接受的。
對於這條sql語句,我檢視了對應的索引資訊,發現沒有符合的索引列。
INDEX_NAME                     TABLESPACE INDEX_TYPE UNIQUENES PAR COLUMN_LIST                    TABLE_TYPE STATUS   NUM_ROWS LAST_ANAL G
------------------------------ ---------- ---------- --------- --- ------------------------------ ---------- ------ ---------- --------- -
     COMM_ACTIVITY_PK           INDXS01    NORMAL     UNIQUE    NO  COMM_ACT_ID                    TABLE      VALID     2967610 23-OCT-14 N

然後更進一步,我抓取了近幾天的執行情況。
BEGIN_INTERVAL_TIME            SQL_ID        SUM(CPU_TIME_DELTA) SUM(DISK_READS_DELTA) SUM(EXECUTIONS_TOTAL)   COUNT(*)
------------------------------ ------------- ------------------- --------------------- --------------------- ----------
29-JAN-15 12.51.00.254 AM      4pbpdtw14s7bg            65290070                     1                 10299          1
29-JAN-15 01.00.00.873 AM      4pbpdtw14s7bg            73191873                     0                 10365          1
29-JAN-15 01.10.01.496 AM      4pbpdtw14s7bg            72758932                     0                 10431          1
29-JAN-15 01.20.02.802 AM      4pbpdtw14s7bg            73899773                     0                 10495          1
29-JAN-15 01.30.03.476 AM      4pbpdtw14s7bg            70535269                     0                 10560          1
29-JAN-15 01.40.05.746 AM      4pbpdtw14s7bg            73060894                     0                 10626          1
29-JAN-15 01.50.06.911 AM      4pbpdtw14s7bg            70580265                     0                 10691          1
29-JAN-15 02.00.07.399 AM      4pbpdtw14s7bg            69498430                     0                 10754          1
29-JAN-15 02.10.08.026 AM      4pbpdtw14s7bg            62471507                     0                 10811          1
29-JAN-15 02.20.08.507 AM      4pbpdtw14s7bg            66107955                     0                 10872          1
29-JAN-15 02.30.08.954 AM      4pbpdtw14s7bg            66053960                     0                 10933          1
29-JAN-15 02.40.09.427 AM      4pbpdtw14s7bg            69912367                     0                 10999          1
29-JAN-15 02.50.10.190 AM      4pbpdtw14s7bg            66570877                     0                 11062          1

BEGIN_INTERVAL_TIME            SQL_ID        SUM(CPU_TIME_DELTA) SUM(DISK_READS_DELTA) SUM(EXECUTIONS_TOTAL)   COUNT(*)
------------------------------ ------------- ------------------- --------------------- --------------------- ----------
28-JAN-15 12.50.50.048 AM      4pbpdtw14s7bg            38913085                     0                  2696          1
28-JAN-15 01.00.52.505 AM      4pbpdtw14s7bg            37876244                     0                  2732          1
28-JAN-15 01.10.54.153 AM      4pbpdtw14s7bg            38930083                     0                  2768          1
28-JAN-15 01.20.55.304 AM      4pbpdtw14s7bg            38816100                     0                  2803          1
28-JAN-15 01.30.55.968 AM      4pbpdtw14s7bg            37014377                     0                  2838          1
28-JAN-15 01.40.56.555 AM      4pbpdtw14s7bg            38199193                     0                  2873          1
28-JAN-15 01.50.57.720 AM      4pbpdtw14s7bg            38408164                     0                  2908          1
28-JAN-15 02.00.58.545 AM      4pbpdtw14s7bg            36498453                     0                  2943          1

從執行的情況來看,還是比較頻繁的。從以上的資料就可以表明這條語句對系統造成了一定的影響,需要考慮改進。
改進的思路有兩種,
第一種就是從業務角度來看,是否可以引入主鍵列,如果引入了主鍵列,效能就會得到極大的提升,這樣也從業務上進行了最佳化。
第二種就是考慮增加相應的索引,綜合評估目前的資料分佈情況,來判定是否需要增加相應的索引,使得update語句中的where條件部分相關的列在索引列範圍之內。
我把我的分析傳送給了開發組,很快得到了反饋,他們需要進一步的分析,對我的建議還是認可的。
透過這個案例,我們發現,很多事情時候標準都是活的,不能以看到全表掃描就是效能瓶頸。需要具體問題具體對待,索引,索引列的新增也不能憑感覺,很多時候需要評估是否需要新增索引,新增的索引列是否合理。
新增的索引對現有的系統的影響範圍,明白了這些,才能對這個問題的把握透徹了,把很多潛在的問題都儘量避免。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8494287/viewspace-1440460/,如需轉載,請註明出處,否則將追究法律責任。

相關文章