效能調優:看看這個匪夷所思的執行計劃。

wei-xh發表於2010-06-24
業務人員反映系統很慢。登入作業系統,用TOP命令檢視,發現大量的CPU都飆升到了100%.根據程式PID一步步找到執行的SQL,都是一個SQL導致的,如下:
SELECT AB14.BAE204 AB14_BAE204,
       AB14.BAE214 AB14_BAE214,
       AB14.BAE203 AB14_BAE203,
       AB13.BAZ010 AB14_AAZ010,
       AB13.BAE265 AB14_BAE165,
       AB14.BAE006 AB14_BAE006,
       (CASE
         WHEN AAE140 IN ('31', '35', '37', '3A', '3B') THEN
          '31'
         ELSE
          AAE140
       END) AB14_AAE140,
       SUM(NVL(AB14.BAE101, 0)) AB14_BAE101,
       MAX(TRUNC(AB14.AAB191, 'DD')) AB14_AAB191,
       MAX(AB14.AAE011) AB14_AAE011
  FROM AB14, AB13
WHERE AB14.BAE204 = AB13.BAE204
   AND NVL(BAE171, '0') = '1'
   AND NVL(BAE205, 0) = 0
   AND AB13.BAE265 = '1'
   AND AB14.AAE140 = '11'
   AND AB13.AAE036 >= TO_DATE('2010-06-01', 'YYYY-MM-DD')
   AND AB13.AAE036 < TO_DATE('2010-06-24', 'YYYY-MM-DD') + 1
GROUP BY AB14.BAE204,
          AB14.BAE214,
          AB14.BAE203,
          AB13.BAZ010,
          AB13.BAE265,
          AB14.BAE006,
          (CASE
            WHEN AAE140 IN ('31', '35', '37', '3A', '3B') THEN
             '31'
            ELSE
             AAE140
          END)
;
檢視執行計劃:
執行計劃
----------------------------------------------------------
Plan hash value: 2048427295

-------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                 |     1 |    99 |     8  (13)| 00:00:01 |
|   1 |  HASH GROUP BY                |                 |     1 |    99 |     8  (13)| 00:00:01 |
|   2 |   NESTED LOOPS                |                 |     1 |    99 |     7   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS BY INDEX ROWID| AB13            |     1 |    22 |     4   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN          | IDX_AB13_AAE036 |     1 |       |     3   (0)| 00:00:01 |
|*  5 |    TABLE ACCESS BY INDEX ROWID| AB14            |     1 |    77 |     3   (0)| 00:00:01 |
|*  6 |     INDEX RANGE SCAN          | IND_AB14        |     2 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("AB13"."BAE265"='1')
   4 - access("AB13"."AAE036">=TO_DATE(' 2010-06-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')
              AND "AB13"."AAE036"   6 - access(NVL("BAE205",0)=0 AND NVL("BAE171",'0')='1' AND "AB14"."AAE140"='11' AND
              "AB14"."BAE204"="AB13"."BAE204")


從執行計劃來看,這個SQL不應該出現效能問題,莫非是CBO評估出現了問題。給SQL增加HINT/*+ gather_plan_statistics */,再次執行。執行了18: 42.75,將近19分鐘。
SQL> select * from table(dbms_xplan.display_cursor(null,null,'iostats last'));
Plan hash value: 2048427295

--------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
--------------------------------------------------------------------------------------------------------------------
|   1 |  HASH GROUP BY                |                 |      1 |      1 |    730 |00:18:14.73 |      16M|      3 |
|   2 |   NESTED LOOPS                |                 |      1 |      1 |   2974 |00:19:03.76 |      16M|      3 |
|*  3 |    TABLE ACCESS BY INDEX ROWID| AB13            |      1 |      1 |   9790 |00:00:00.24 |   13301 |      3 |
|*  4 |     INDEX RANGE SCAN          | IDX_AB13_AAE036 |      1 |      1 |  21607 |00:00:00.06 |     125 |      0 |
|*  5 |    TABLE ACCESS BY INDEX ROWID| AB14            |   9790 |      1 |   2974 |00:18:02.19 |      16M|      0 |
|*  6 |     INDEX RANGE SCAN          | IND_AB14        |   9790 |      2 |    582M|00:09:43.72 |    2398K|      0 |
--------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("AB13"."BAE265"='1')
   4 - access("AB13"."AAE036">=TO_DATE(' 2010-06-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "AB13"."AAE036"   5 - filter("AB14"."BAE204"="AB13"."BAE204")
   6 - access("AB14"."SYS_NC00031$"=0 AND "AB14"."SYS_NC00032$"='1' AND "AAE140"='11')

匪夷所思的事情發生了:
1)看ID=6的A-Rows列,實際透過索引IND_AB14返回的行數高達582M行。而評估出來的只有兩條。檢視統計資訊都不缺失。
2)IND_AB14是一個函式索引。建立語句如下:create index IND_AB14 on AB14 (NVL(BAE205,0), NVL(BAE171,'0'), AAE140),但是看執行計劃的謂詞部分(id為6的行),"AB14"."SYS_NC00031$"=0 AND "AB14"."SYS_NC00032$"='1'從何而來啊,索引裡是沒有這兩個列的資訊的。貌似SYS_NC00031$對於的是NVL("BAE205",0),SYS_NC00032$對於的是NVL("BAE171",'0')。
3)我用語句查詢了一下,根據索引應該返回的行數。

SQL> SELECT COUNT(*) FROM ab14 WHERE  NVL(BAE171, '0') = '1' AND NVL(BAE205, 0) = 0 AND aae140='11';

  COUNT(*)
----------
     59623
只有不到六萬的資料量,怎麼實際返回了582M的資料。


不過從執行計劃ID=5行可以看出根據"AB14"."BAE204"="AB13"."BAE204"可以過濾掉大量資料,於是修改了之前的函式索引增加了BAE204這個欄位。
create index IND_AB14 on AB14 (NVL(BAE205,0), NVL(BAE171,'0'), AAE140,bae204)

修改索引後,重新執行,只花了2.3秒。
Plan hash value: 1600515523

--------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
--------------------------------------------------------------------------------------------------------------------
|   1 |  HASH GROUP BY                |                 |      1 |      1 |    743 |00:00:00.37 |   33700 |     55 |
|   2 |   NESTED LOOPS                |                 |      1 |      1 |   3073 |00:00:00.31 |   33700 |     55 |
|*  3 |    TABLE ACCESS BY INDEX ROWID| AB13            |      1 |      1 |   9803 |00:00:00.06 |   13282 |      0 |
|*  4 |     INDEX RANGE SCAN          | IDX_AB13_AAE036 |      1 |      1 |  21624 |00:00:00.02 |     108 |      0 |
|   5 |    TABLE ACCESS BY INDEX ROWID| AB14            |   9803 |      1 |   3073 |00:00:00.27 |   20418 |     55 |
|*  6 |     INDEX RANGE SCAN          | IND_AB14_BAE204 |   9803 |      1 |   3073 |00:00:00.25 |   19619 |     55 |
--------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("AB13"."BAE265"='1')
   4 - access("AB13"."AAE036">=TO_DATE(' 2010-06-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "AB13"."AAE036"   6 - access("AB14"."SYS_NC00031$"=0 AND "AB14"."SYS_NC00032$"='1' AND "AAE140"='11' AND
              "AB14"."BAE204"="AB13"."BAE204"



CBO評估E-Rows依然非常不準確,重新分析表兩個表(僅提供一個AB14的,AB13的略):
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(OWNNAME          => 'NCSI',
                                TABNAME          => 'AB14',
                                ESTIMATE_PERCENT => 100,
                                METHOD_OPT       => 'FOR ALL COLUMNS  SIZE SKEWONLY',
                                CASCADE          => TRUE,
                                DEGREE           => 10);
END;

重新執行檢視執行計劃:
Plan hash value: 1600515523

--------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
--------------------------------------------------------------------------------------------------------------------
|   1 |  HASH GROUP BY                |                 |      1 |      1 |    743 |00:00:00.23 |   33709 |      2 |
|   2 |   NESTED LOOPS                |                 |      1 |      1 |   3073 |00:00:00.20 |   33709 |      2 |
|*  3 |    TABLE ACCESS BY INDEX ROWID| AB13            |      1 |      1 |   9806 |00:00:00.06 |   13285 |      1 |
|*  4 |     INDEX RANGE SCAN          | IDX_AB13_AAE036 |      1 |      1 |  21628 |00:00:00.02 |     108 |      0 |
|   5 |    TABLE ACCESS BY INDEX ROWID| AB14            |   9806 |      1 |   3073 |00:00:00.11 |   20424 |      1 |
|*  6 |     INDEX RANGE SCAN          | IND_AB14_BAE204 |   9806 |      1 |   3073 |00:00:00.09 |   19625 |      0 |
--------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("AB13"."BAE265"='1')
   4 - access("AB13"."AAE036">=TO_DATE(' 2010-06-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "AB13"."AAE036"   6 - access("AB14"."SYS_NC00031$"=0 AND "AB14"."SYS_NC00032$"='1' AND "AAE140"='11' AND
              "AB14"."BAE204"="AB13"."BAE204")

幾乎沒任何改善。評估出來的依然很差。


[ 本帖最後由 wei-xh 於 2010-6-24 17:12 編輯 ]

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

相關文章