索引重建的資料來源(二)

yangtingkun發表於2011-12-04

對這個問題有了進一步的認識。

索引重建的資料來源:http://yangtingkun.itpub.net/post/468/457384

 

 

上一篇文章測試的結果認為DDL也是基於CBO的,但是今天發現問題並非如此。Oracle在評估REBUILD索引時並不是根據統計資訊,而是根據資料字典中非索引欄位的長度:

SQL> create table t_rebuild (id number, flag char(1));

Table created.

SQL> insert into t_rebuild select rownum, 'a' from dba_objects;

15695 rows created.

SQL> commit;

Commit complete.

SQL> create index ind_t_rebuild_id on t_rebuild(id);

Index created.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 3014377519

-------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |    82 |  1066 |     2   (0)| 00:00:01 |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |       |       |            |          |
|   2 |   SORT CREATE INDEX    |                  |    82 |  1066 |            |          |
|   3 |    TABLE ACCESS FULL   | T_REBUILD        |    82 |  1066 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

10 rows selected.

SQL> alter table t_rebuild modify (flag char(2));

Table altered.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 3014377519

-------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |  2288 | 29744 |     7   (0)| 00:00:01 |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |       |       |            |          |
|   2 |   SORT CREATE INDEX    |                  |  2288 | 29744 |            |          |
|   3 |    TABLE ACCESS FULL   | T_REBUILD        |  2288 | 29744 |     7   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

10 rows selected.

SQL> alter table t_rebuild modify (flag char(3));

Table altered.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 43729923

-------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |  4738 | 61594 |    13   (0)| 00:00:01 |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |       |       |            |          |
|   2 |   SORT CREATE INDEX    |                  |  4738 | 61594 |            |          |
|   3 |    INDEX FAST FULL SCAN| IND_T_REBUILD_ID |       |       |            |          |
-------------------------------------------------------------------------------------------

10 rows selected.

隨著非索引列的長度增加,重建索引的執行計劃由全表掃描變成了索引快速全掃。

整個過程並沒有收集過表或索引的統計資訊,但是執行計劃已經發生了改變,下面嘗試關閉統計資訊動態收集,以及設定表和列屬性的方式影響執行計劃:

SQL> alter session set optimizer_dynamic_sampling = 0;

Session altered.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------
Plan hash value: 43729923

-------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |  4738 | 61594 |    13   (0)| 00:00:01 |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |       |       |            |          |
|   2 |   SORT CREATE INDEX    |                  |  4738 | 61594 |            |          |
|   3 |    INDEX FAST FULL SCAN| IND_T_REBUILD_ID |       |       |            |          |
-------------------------------------------------------------------------------------------

10 rows selected.

SQL> exec dbms_stats.set_table_stats(user, 'T_REBUILD', numrows => 1, numblks => 1, avgrlen => 2)

PL/SQL procedure successfully completed.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 43729923

-------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |     1 |     2 |     2   (0)| 00:00:01 |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |       |       |            |          |
|   2 |   SORT CREATE INDEX    |                  |     1 |     2 |            |          |
|   3 |    INDEX FAST FULL SCAN| IND_T_REBUILD_ID |       |       |            |          |
-------------------------------------------------------------------------------------------

10 rows selected.

SQL> exec dbms_stats.set_column_stats(user, 'T_REBUILD', 'FLAG', avgclen => 1)

PL/SQL procedure successfully completed.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 43729923

-------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |     1 |     2 |     2   (0)| 00:00:01 |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |       |       |            |          |
|   2 |   SORT CREATE INDEX    |                  |     1 |     2 |            |          |
|   3 |    INDEX FAST FULL SCAN| IND_T_REBUILD_ID |       |       |            |          |
-------------------------------------------------------------------------------------------

10 rows selected.

很明顯DDL執行計劃的確定其實和統計資訊沒有什麼關係,而完全是根據資料字典確定的。因此這實際上也是一種RULE,只不過Oracle將這個條件寫到了最佳化器中,如果將最佳化器設定為RULEOracle同樣可以做出相同的判斷:

SQL> alter session set optimizer_mode = rule;

Session altered.

SQL> drop table t_rebuild purge;

Table dropped.

SQL> create table t_rebuild (id number, flag char(1));

Table created.

SQL> insert into t_rebuild select rownum, 'a' from dba_objects;

15695 rows created.

SQL> commit;

Commit complete.

SQL> create index ind_t_rebuild_id on t_rebuild(id);

Index created.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------
Plan hash value: 3014377519

---------------------------------------------------
| Id  | Operation              | Name             |
---------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |
|   2 |   SORT CREATE INDEX    |                  |
|   3 |    TABLE ACCESS FULL   | T_REBUILD        |
---------------------------------------------------

Note
-----
   - rule based optimizer used (consider using cbo)

14 rows selected.

SQL> alter table t_rebuild modify flag char(3);

Table altered.

SQL> explain plan for alter index ind_t_rebuild_id rebuild;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
Plan hash value: 43729923

---------------------------------------------------
| Id  | Operation              | Name             |
---------------------------------------------------
|   0 | ALTER INDEX STATEMENT  |                  |
|   1 |  INDEX BUILD NON UNIQUE| IND_T_REBUILD_ID |
|   2 |   SORT CREATE INDEX    |                  |
|   3 |    INDEX FAST FULL SCAN| IND_T_REBUILD_ID |
---------------------------------------------------

Note
-----
   - rule based optimizer used (consider using cbo)

14 rows selected.

不過由於很多DDL操作對於的表或物件本身就沒有統計資訊,完全使用CBO是不現實的,也是不準確的,所以採用這種基於規則的執行計劃也是有道理的。不過事實上,對於DDL而言,有多種執行計劃可選擇的其實也並不多。

 

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

相關文章