oracle在什麼時候使用索引

正常情況下,一條SQL語句使用索引,在的where謂語條件中要出索引的左邊部分(where條件出現字段從建索引的字段的順序左邊字段開始,例如:create index ind on table(column1,column2,column3),只有where條件出現了下列謂語:column1、column1,column2、column1,column2,column3;纔會使用索引。

創建表T

create table t as select decode(mod(rownum,2),0,'F',2,'M') flag,t.* from all_objects t;
commit;

創建索引
create index ind_t on t(flag,object_id);

獲取統計數據
analyze table t compute statistics;
analyze index ind_t compute statistics;


情況一:快速全面掃描索引:因爲需要查詢的和where語句所關聯的字段都在索引中,並且索引一般比表小得多。從而減少物理IO,提高查詢性能,
SQL> set autot traceonly exp
SQL> select flag,object_id from t;
執行計劃
----------------------------------------------------------
Plan hash value: 1148684643
------------------------------------------------------------------------------
| Id  | Operation            | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |       | 70636 |   344K|    48   (0)| 00:00:01 |
|   1 |  INDEX FAST FULL SCAN| IND_T | 70636 |   344K|    48   (0)| 00:00:01 |
------------------------------------------------------------------------------
SQL>

情況二:索引跳躍式掃描:如果索引的左邊鍵值非常基數非常少,優化器會使用這種方式檢索。

SQL> select flag,object_id from t where object_id=1231;
執行計劃
----------------------------------------------------------
Plan hash value: 3688940926
--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       |     1 |     5 |     2   (0)| 00:00:01 |
|*  1 |  INDEX SKIP SCAN | IND_T |     1 |     5 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("OBJECT_ID"=1231)
       filter("OBJECT_ID"=1231)

SQL> select * from t where object_id=100;
 
 select * from t where object_id<100;這個使用跳越索引

select * from t where object_id>100;這個走全表掃描

索引是否使用索引 oracle會根據獲取數據塊數佔總行數大小(對於有一些表大於多塊讀的塊個數的表)

修改索引左邊的字段,讓他的基數更高

alter table t modify flag varchar2(10);

update t set flag=to_char(mod(rownum,10000)) ;

收集統計信息

 exec dbms_stats.gather_table_stats(user,'T',cascade=>true);

select * from t where object_id=1231;  這樣就可能不走跳躍索引


情況三:行數統計

select count(*) from t

可能不會考慮直接遍歷索引,因爲在B樹索引中,存在null。


情況四:索引列上使用函數

select * from t where fun(index_columns)=223;

因爲索引列上使用的函數,索引不能直接使用索引列直接創建的索引,應該使用這個函數所對應的函數索引,並且這個函數是deterministic類性

情況五:索引列顯示或者隱式轉換

select * from t where  index_column=5;

如果index_column是一個字符類型,這樣相當如oracle調用了to_number(index_column)=5,從而無法使用索引


SQL> explain plan for select * from t where flag=3;
已解釋。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1601196873


--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   495 | 51975 |  2075   (1)| 00:00:25 |
|*  1 |  TABLE ACCESS FULL| T    |   495 | 51975 |  2075   (1)| 00:00:25 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
   1 - filter(TO_NUMBER("FLAG")=3)

已選擇13行。

SQL> explain plan for select /*+ index(t ind_t)*/ * from t where flag=3;
已解釋。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1099373541
--------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time|

--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |   495 | 51975 |  2491   (1)| 00:00:30 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |   495 | 51975 |  2491   (1)| 00:00:30 |
|*  2 |   INDEX FULL SCAN           | IND_T |   495 |       |  1998   (1)| 00:00:24 |
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_NUMBER("FLAG")=3)
已選擇14行。


SQL> explain plan for select * from t where flag='3';

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

PLAN_TABLE_OUTPUT

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

| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time
|   0 | SELECT STATEMENT            |       |   495 | 51975 |   497   (0)| 00:00:06 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |   495 | 51975 |   497   (0)| 00:00:06 |
|*  2 |   INDEX RANGE SCAN          | IND_T |   495 |       |     4   (0)| 00:00:01 |

在where謂語條件中,減少對數據列使用函數

情況六:根據統計表的大小和訪問數據量來決定是否使用索引

根據統計信息,oracle會假設數據分佈均勻,獲取的信息不僅僅包含索引。

1、如果獲取的數據佔總行數的非常小比例,並且這張表非常大,這時會使用索引。

2、如果獲取的數據佔總行數的非常大比例,或者數據表非常小,這時會使用全表掃描。










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章