根據索引的類型與where限制條件的不同,有4種類型的Oracle索引掃描: 3,4可歸一種
(1) 索引唯一掃描(index uniquescan)
(2) 索引範圍掃描(index range scan)
(3) 索引全掃描(index full scan)
(4) 索引快速掃描(index fast full scan)
(5) 索引跳躍掃描(INDEXSKIP SCAN)
一. 索引唯一掃描(index unique scan)
通過唯一索引查找一個數值經常返回單個ROWID,存在UNIQUE 或PRIMARY KEY 約束(它保證了語句只存取單行)的話,Oracle經常實現唯一性掃描
1 必須是通過唯一索引【UNIQUE】來訪問數據;
2 通過唯一索引來訪問數據時,每次返回的記錄數必須是1條;
3 WHERE從句中必須要用等值【=】條件來過濾數據:
注意:表中某個字段是唯一的,如果該字段上的索引不是唯一的,那麼CBO選擇的將是通過INDEX RANGE SCAN的路徑來訪問數據。想要表達的是,真實場景下這種情況的確會存在,因爲有些系統是通過應用程序來保證表中的字段唯一,而並沒有在表上對應的字段上通過創建唯一約束或者是唯一索引來保證數據的唯一性。那麼,這樣的話,將會導致CBO在選擇執行計劃的情況下,有可能會出現偏差。所以,對於這種情況下,即使應用程序可以保證數據的唯一性,最好還是在表上創建一個唯一索引比較穩妥。
例子:
SQL> create table t as select * from dba_objects where object_id is not null;
表已創建。
SQL> alter table t modify (object_id not null);
表已更改。
SQL> create unique index index_t on t(object_id);
索引已創建。
SQL> select * from t a where a.object_id=75780;
執行計劃
----------------------------------------------------------
Plan hash value: 4119349871
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 207 | 2 (0)| 00:
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 207 | 2 (0)| 00:
|* 2 | INDEX UNIQUE SCAN | INDEX_T | 1 | | 1 (0)| 00:
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("A"."OBJECT_ID"=75780)
統計信息
----------------------------------------------------------
6 recursive calls
0 db block gets
12 consistent gets
1 physical reads
0 redo size
1348 bytes sent via SQL*Net to client
404 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
二.索引範圍掃描(index range scan)
使用一個索引存取多行數據,或者創建索引時沒有提字爲unique索引,即使返一行記錄也走範圍掃描.
使用index rang scan的3種情況:
(a) 在唯一索引列上使用了range操作符(> < <> >= <= between)。
(b) 在組合索引上(unique index),只使用部分列進行查詢,導致查詢出多行。
(c) 對非唯一索引列上進行的任何查詢。
例子:
SQL> create table t as select * from dba_objects where object_id is not null;
表已創建。
SQL> alter table t modify (object_id not null);
表已更改。
SQL> create index index_t on t(object_id);
索引已創建。
SQL> set wrap off;
SQL> set autotrace traceonly;
SQL> select * from t a where a.object_id = 75780;
Plan hash value: 80339723
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 207 | 2 (0)| 00:
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 207 | 2 (0)| 00:
|* 2 | INDEX RANGE SCAN | INDEX_T | 1 | | 1 (0)| 00:
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("A"."OBJECT_ID"=75780)
Note
-----
- dynamic sampling used for this statement (level=2)
統計信息
----------------------------------------------------------
37 recursive calls
0 db block gets
118 consistent gets
1 physical reads
0 redo size
1444 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
三. 索引全掃描(index full scan ) 索引快速掃描(index fast full scan)
索引全掃描(index full scan )
與全表掃描對應,也有相應的全Oracle索引掃描。在某些情況下,可能進行全Oracle索引掃描而不是範圍掃描,需要注意的是全Oracle索引掃描只在CBO模式下才有效。 CBO根據統計數值得知進行全Oracle索引掃描比進行全表掃描更有效時,才進行全Oracle索引掃描,而且此時查詢出的數據都必須從索引中可以直接得到。
例子:
SQL> create table t3 as select * from dba_objects where object_id is not null;
表已創建。
SQL> alter table t3 modify(object_id not null);
表已更改。
SQL> create index index_t3 on t3(object_id);
索引已創建。
SQL> set autotrace trraceonly;
SQL> select /*+index(t index_t3) */ object_id from t3 t;
已選擇114164行。
執行計劃
----------------------------------------------------------
Plan hash value: 3077935993
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 114K| 1451K| 270 (1)| 00:00:04 |
| 1 | INDEX FULL SCAN | INDEX_T3 | 114K| 1451K| 270 (1)| 00:00:04 |
-----------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
統計信息
----------------------------------------------------------
5 recursive calls
0 db block gets
7916 consistent gets
0 physical reads
0 redo size
1663703 bytes sent via SQL*Net to client
84126 bytes received via SQL*Net from client
7612 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
114164 rows processed
索引快速掃描(index fast full scan)
掃描索引中的所有的數據塊,與 index full scan很類似,在這種存取方法中,可以使用多塊讀功能,也可以使用並行讀入,以便獲得最大吞吐量與縮短執行時間。
SQL> select object_id from t3;
已選擇114164行。
執行計劃
----------------------------------------------------------
Plan hash value: 448706225
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 114K| 1451K| 74 (0)| 00:00:01
| 1 | INDEX FAST FULL SCAN| INDEX_T3 | 114K| 1451K| 74 (0)| 00:00:01
--------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
統計信息
----------------------------------------------------------
19 recursive calls
0 db block gets
7931 consistent gets
253 physical reads
0 redo size
1663703 bytes sent via SQL*Net to client
84126 bytes received via SQL*Net from client
7612 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
114164 rows processed
index full scan的時候oracle定位到索引的root block,然後到branch block(如果有的話),再定位到第一個leaf block, 然後根據leaf block的雙向鏈表順序讀取。它所讀取的塊都是有順序的,也是經過排序的。
index fast full scan則不同,它是從段頭開始,讀取包含位圖塊,root block,所有的branch block, leaf block,讀取的順序完全有物理存儲位置決定,並採取多塊讀,每次讀取db_file_multiblock_read_count個塊。
使用這兩種索引掃描需要表的索引字段至少有一個是not null限制。快速全索引掃描比普通索引掃描速度快是因爲快速索引掃描能夠多塊讀取,並且能並行處理。
四. 索引跳躍掃描(INDEX SKIP SCAN)
索引跳躍掃描主要發生在對複合索引的列進行過濾時,沒有寫上先導列,並且先導列中的重複值較多,而非先導列中的重複數據較少。
SQL> create table t5 as select t.*,rownum id from user_tables t;
表已創建。
SQL> create index index_t5 on t5(table_name,id) ;
索引已創建。
SQL> begin
2 dbms_stats.gather_table_stats(ownname =>'BOC_RWA3' ,tabname => 'T5' );
3 end;
4 /
PL/SQL 過程已成功完成。
當在where 條件中出現前導列時爲INDEX RANGE SCAN
select * from t5 t where table_name = 'T1';
執行計劃
----------------------------------------------------------
Plan hash value: 1915796132
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 214 | 3 (0)| 00
| 1 | TABLE ACCESS BY INDEX ROWID| T5 | 1 | 214 | 3 (0)| 00
|* 2 | INDEX RANGE SCAN | INDEX_T5 | 1 | | 2 (0)| 00
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("TABLE_NAME"='T1')
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
4144 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
當在where 條件中出現非前導列時爲INDEX SKIP SCAN
SQL> select * from t5 t where id = 10;
執行計劃
----------------------------------------------------------
Plan hash value: 2396816619
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 214 | 11 (0)| 00
| 1 | TABLE ACCESS BY INDEX ROWID| T5 | 1 | 214 | 11 (0)| 00
|* 2 | INDEX SKIP SCAN | INDEX_T5 | 1 | | 10 (0)| 00
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=10)
filter("ID"=10)
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
13 consistent gets
0 physical reads
0 redo size
4153 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
-----------------------------------------------------------
禁用skip scan:
alter system set “_optimizer_skip_scan_enabled” = false scope=spfile;