11g組合索引的統計資訊會用於對錶返回基數的計算

westzq1984發表於2013-04-17

10g的時候,CBO計算表返回多少資料,最簡單的情況就是各個列的DENSITY的乘積,不會用到索引的資訊。如果相關的2列之間有依賴關係,從統計資訊上是無法反應的。

11g新增了一個組合列統計的功能的功能,今天在測試時,發現組合索引的統計資訊,其實也用於了CBO計算表的card

 

測試的表,沒有收集直方圖

 

如下是沒有建立ID4ID5上組合索引的情況

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4=5 AND id5=5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

 

Plan hash value: 2261054565

 

--------------------------------------------------------------------------------------------

| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |              |    10 |   720 |  1005   (0)| 00:00:13 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| TEST         |    10 |   720 |  1005   (0)| 00:00:13 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_ID4 |  1000 |       |     5   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------

 

可以看到Table Access Card = 10 ,這是通過 錶行數 * ID4選擇率 * ID5選擇率 = 1000000 * .001000 * .010000 = 10

 

 

建立一個組合索引

CREATE INDEX idx_test_id45 ON TEST(id4,id5)

 

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4=5 AND id5=5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

 

Plan hash value: 3852160031

 

---------------------------------------------------------------------------------------------

| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |               |  1000 | 72000 |  1005   (0)| 00:00:13 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST          |  1000 | 72000 |  1005   (0)| 00:00:13 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_ID45 |  1000 |       |     5   (0)| 00:00:01 |

---------------------------------------------------------------------------------------------

 

可以看到Table Access Card = 1000,這是通過錶行數 * 組合索引的選擇率 = 1000000 * (1/1000) = 1000

 

還可以看到,就算不用索引,索引的DISTINCT值,也已經進入了基數計算

 

SQL> EXPLAIN PLAN FOR SELECT /*+full(A)*/ * FROM ctais2.TEST A WHERE id4=5 AND id5=5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

 

Plan hash value: 1357081020

 

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |  1000 | 72000 |  2165   (1)| 00:00:26 |

|*  1 |  TABLE ACCESS FULL| TEST |  1000 | 72000 |  2165   (1)| 00:00:26 |

--------------------------------------------------------------------------

 

開始懷疑建立索引,預設可能收集了複合列統計資訊,可是查詢了dba_stat_extensions以及其下的基表,都沒有發現什麼有價值的資訊。

 

嘗試修改索引的統計資訊:為了避免DBMS_STATS可能遞迴修改其他的資料,我選擇了直接UPDATE

SQL> UPDATE ind$ SET distkey=2000 WHERE obj#=80692;

 

1 row updated.

 

SQL> commit;

 

Commit complete.

 

SQL> alter system flush shared_pool;

 

System altered.

 

SQL> EXPLAIN PLAN FOR SELECT /*+full(A)*/ * FROM ctais2.TEST A WHERE id4=5 AND id5=5;

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

 

Plan hash value: 1357081020

 

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |   500 | 36000 |  2165   (1)| 00:00:26 |

|*  1 |  TABLE ACCESS FULL| TEST |   500 | 36000 |  2165   (1)| 00:00:26 |

--------------------------------------------------------------------------

 

可以看到,返回的Card確實降低為了以前的1/2

 

如果除去索引外,還有其他謂詞,也可以使用組合索引的統計

 

SQL> EXPLAIN PLAN FOR SELECT /*+full(A)*/ * FROM ctais2.TEST A WHERE id4=5 AND id5=5 AND id3=5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 1357081020

 

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |   250 | 18000 |  2165   (1)| 00:00:26 |

|*  1 |  TABLE ACCESS FULL| TEST |   250 | 18000 |  2165   (1)| 00:00:26 |

--------------------------------------------------------------------------

 

250 = 1000000 * (1/2000) * 0.5 = 錶行數 * 組合索引的選擇率 * ID3選擇率

 

什麼時候無法使用索引的統計資訊來計算表的返回CARD

 

1.組合索引列非等值查詢

 

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4=5 AND id5<5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 3852160031

 

---------------------------------------------------------------------------------------------

| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |               |    51 |  3672 |    54   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST          |    51 |  3672 |    54   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_ID45 |    51 |       |     3   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------

 

 

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4<5 AND id5=5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 2874578131

 

---------------------------------------------------------------------------------------------

| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |               |    50 |  3600 |    65   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST          |    50 |  3600 |    65   (0)| 00:00:01 |

|*  2 |   INDEX SKIP SCAN           | IDX_TEST_ID45 |    50 |       |    14   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------

 

刪除索引後:

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4=5 AND id5<5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 2261054565

 

--------------------------------------------------------------------------------------------

| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |              |    51 |  3672 |  1005   (0)| 00:00:13 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| TEST         |    51 |  3672 |  1005   (0)| 00:00:13 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_ID4 |  1000 |       |     5   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------

 

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4<5 AND id5=5;

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 1357081020

 

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |    50 |  3600 |  2165   (1)| 00:00:26 |

|*  1 |  TABLE ACCESS FULL| TEST |    50 |  3600 |  2165   (1)| 00:00:26 |

--------------------------------------------------------------------------

 

可以看到Rows沒有任何變化。

這時候CARD的計算為:

id4=5 AND id5<5 => 1000000 * 0.001 * (5-0)/(99-0) = 50.51 = 51

id4<5 AND id5=5 => 1000000 * (5-0)/(999-0) * 0.01 = 50.05 = 50

 

2.組合索引的列,收集了直方圖

 

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4=5 AND id5=5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 3852160031

 

---------------------------------------------------------------------------------------------

| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |               |    10 |   720 |    13   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST          |    10 |   720 |    13   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_ID45 |    10 |       |     3   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------

 

SQL> EXEC dbms_stats.delete_column_stats('ctais2','TEST','ID5',col_stat_type => 'HISTOGRAM');

 

PL/SQL procedure successfully completed.

 

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4=5 AND id5=5;

 

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 3852160031

 

---------------------------------------------------------------------------------------------

| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |               |    10 |   720 |    13   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST          |    10 |   720 |    13   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_ID45 |    10 |       |     3   (0)| 00:00:01 |

---------------------------------------------------------------------------------------------

 

SQL> EXEC dbms_stats.delete_column_stats('ctais2','TEST','ID4',col_stat_type => 'HISTOGRAM');

 

PL/SQL procedure successfully completed.

 

2列上的直方圖都刪除後

SQL> EXPLAIN PLAN FOR SELECT * FROM ctais2.TEST A WHERE id4=5 AND id5=5;

Explained.

 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 3852160031

 

---------------------------------------------------------------------------------------------

| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |               |  1000 | 72000 |  1005   (0)| 00:00:13 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST          |  1000 | 72000 |  1005   (0)| 00:00:13 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_ID45 |  1000 |       |     5   (0)| 00:00:01 |

---------------------------------------------------------------------------------------------

Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE

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

相關文章