另我無語啊,SQL執行計劃走錯

wei-xh發表於2011-06-02
今天早上以前出過故障的SQL執行計劃又走錯了。這個SQL併發很大,當時看到滿屏的全表掃描SQL執行,哥有點不淡定。
可MB的這個SQL不該走錯了。
第一,我用了baseline.

第二,當時我看了全表掃描的cost>>索引的cost.

第三,表的統計資訊都有

SQL如下:
SELECT count(*)
  FROM EN_GS_SERV_SERVICE_FDT0 a
/*no open this function*/
WHERE 1 = 1
   and GLOBAL_ID = :1;

統計資訊如下:
TABLE_NAME                  NUM_ROWS     BLOCKS AVG_ROW_LEN TO_CHAR(LAST_ANALYZED,'MM/DD/YYYYHH24:
------------------------- ---------- ---------- ----------- --------------------------------------
EN_GS_SERV_SERVICE_FDT0      6760748     250944         258 04/18/2011 10:39:41


COLUMN_NAME          NUM_DISTINCT
-------------------- ------------

GLOBAL_ID                 1000000

索引統計資訊如下:
name                                                           NUM_ROWS   distinct LEAF_BLOCKS         cf      level   alfbpkey
------------------------------------------------------------ ---------- ---------- ----------- ---------- ---------- ----------
EN_GS_SERV_SRV_FDT0_GID_IND                                     6755994     121058       16340    6755952          2          1


是的,索引的聚簇因子是非常大,和錶行數接近,可關鍵是這個SQL是count(*)操作,而且謂詞只有一個,就是索引的。根本跟聚簇因子半毛錢關係都沒有,因為不需要回表。當時雖然萬分緊急,還是淡定的看了下走索引的cost,只有3,只有3啊,全表的都過萬了,MB的。

出問題的時候,explain plan 出來的預設執行計劃是全表掃描
----------------------------------------------------------------------------------------------
| Id  | Operation          | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                         |     1 |     7 | 55226   (1)| 00:11:03 |
|   1 |  SORT AGGREGATE    |                         |     1 |     7 |            |          |
|*  2 |   TABLE ACCESS FULL| EN_GS_SERV_SERVICE_FDT0 |     7 |    49 | 55226   (1)| 00:11:03 |
----------------------------------------------------------------------------------------------

我加了索引的hint,檢視cost,只有3
-------------------------------------------------------------------------------------------------
| Id  | Operation         | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                             |     1 |     7 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |                             |     1 |     7 |            |          |
|*  2 |   INDEX RANGE SCAN| EN_GS_SERV_SRV_FDT0_GID_IND |     7 |    49 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

更關鍵的是。這個SQL有baseline。但是當時沒用到。這更是讓我費解的。
透過如下方法讓執行計劃失效:
begin
  dbms_stats.set_column_stats(ownname       => 'dhw',
                              tabname       => 'EN_GS_SERV_SERVICE_FDT0',
                              force         => true,
                              colname       => 'GLOBAL_ID',
                              distcnt       => 10000000);
end;
/

重新explain plan for,走對了。而且baseline也自己用上了。
太讓我費解了。

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

相關文章