官方文檔:
Full Index Scan
In a full index scan, the database reads the entire index in order. A full index scan is available if a predicate (WHERE clause) in the SQL statement references a column in the index, and in some circumstances when no predicate is specified. A full scan can
eliminate sorting because the data is ordered by index key.
Fast Full Index Scan
A fast full index scan is a full index scan in which the database reads the index blocks in no particular order. The database accesses the data in the index itself, without accessing the table.
Fast full index scans are an alternative to a full table scan when the index contains all the columns that are needed for the query, and at least one column in the index key has the NOT NULL constraint.
理解:
full index scan:想要的結果是有序,讀取數據塊是一塊一塊的操作,他會從索引的根節點向下掃描到葉子節點,然後使用雙向列表的方式順序讀取數據塊。
fast full index scan:想要的結果是無序的,讀取數據塊是multiple I/O操作,從根幾點開始向下掃描到葉子節點後使用的是單次I/O讀取多個數據塊。
例子:
index fast full scan與index full scan試驗
--創建測試表test3
SQL> create table test3 as select * from dba_objects;
表已創建。
--創建索引
SQL> create index idx_test3_id on test3(object_id);
索引已創建。
--收集test3的統計信息
SQL> exec dbms_stats.gather_table_stats('SYSTEM','TEST3',cascade=>true);
PL/SQL 過程已成功完成。
SQL> set autot traceonly;
SQL> select object_id from test3;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 3306317399
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71947 | 351K| 280 (1)| 00:00:04 |
| 1 | TABLE ACCESS FULL| TEST3 | 71947 | 351K| 280 (1)| 00:00:04 |
---------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
5760 consistent gets
0 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71947 rows processed
--我們看見上面的執行計劃走了全表掃描,這是因爲沒有對oracle索引中不會存儲null值,
而我們的查詢中有要返回所有的值,索引會走全表掃面。
--如果此時加上限定條件 where objec_id is not null 則會走 index fast full scan
-更改列object_id屬性爲 not null
SQL> alter table test3 modify (object_id not null);
表已更改。
SQL> select object_id from test3;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 1226029696
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71947 | 351K| 45 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| IDX_TEST3_ID | 71947 | 351K| 45 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
統計信息
----------------------------------------------------------
208 recursive calls
0 db block gets
4982 consistent gets
0 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
71947 rows processed
--如上所示,限定爲not null 後走了index fast full scan
--添加限定條加走 index full scan
SQL> select /*+ index(test3 idx_test3_id) */ object_id from test3;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 3789893995
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71947 | 351K| 160 (0)| 00:00:02 |
| 1 | INDEX FULL SCAN | IDX_TEST3_ID | 71947 | 351K| 160 (0)| 00:00:02 |
---------------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4946 consistent gets
0 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71947 rows processed
--添加order by也會走index full scan,這裏會注意到index full scan的開銷是160,
而index fast full scan的開銷只有45
SQL> select object_id from test3 order by object_id;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 3789893995
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71947 | 351K| 160 (0)| 00:00:02 |
| 1 | INDEX FULL SCAN | IDX_TEST3_ID | 71947 | 351K| 160 (0)| 00:00:02 |
---------------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4946 consistent gets
0 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71947 rows processed
--添加hint使帶有order by字句的查詢強制走index fast full scan,
但是注意cast情況還是和index full scan大致相同
SQL> select /*+ index_ffs(test3 idx_test3_id) */ object_id from test3 order by o
bject_id;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 1094006042
--------------------------------------------------------------------------------
--------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CP
U)| Time |
--------------------------------------------------------------------------------
--------------
| 0 | SELECT STATEMENT | | 71947 | 351K| | 267 (
2)| 00:00:04 |
| 1 | SORT ORDER BY | | 71947 | 351K| 856K| 267 (
2)| 00:00:04 |
| 2 | INDEX FAST FULL SCAN| IDX_TEST3_ID | 71947 | 351K| | 45 (
0)| 00:00:01 |
--------------------------------------------------------------------------------
--------------
統計信息
----------------------------------------------------------
48 recursive calls
0 db block gets
175 consistent gets
1 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
71947 rows processed
SQL> select /*+ index_ffs(test3 idx_test3_id) */ object_id from test3;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 1226029696
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71947 | 351K| 45 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| IDX_TEST3_ID | 71947 | 351K| 45 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4953 consistent gets
0 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71947 rows processed
SQL> alter system flush buffer_cache;
系統已更改。
SQL> select /*+ index_ffs(test3 idx_test3_id) */ object_id from test3;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 1226029696
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71947 | 351K| 45 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| IDX_TEST3_ID | 71947 | 351K| 45 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
統計信息
----------------------------------------------------------
0 recursive calls
0 db block gets
4953 consistent gets
161 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71947 rows processed
--使用hint,提示走全表掃描
SQL> select /*+ full(test3) */ object_id from test3;
已選擇71947行。
執行計劃
----------------------------------------------------------
Plan hash value: 3306317399
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71947 | 351K| 280 (1)| 00:00:04 |
| 1 | TABLE ACCESS FULL| TEST3 | 71947 | 351K| 280 (1)| 00:00:04 |
---------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
5760 consistent gets
1025 physical reads
0 redo size
843616 bytes sent via SQL*Net to client
53148 bytes received via SQL*Net from client
4798 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71947 rows processed
--執行count(*)則會走index fast full scan
SQL> select count(*) from test3;
執行計劃
----------------------------------------------------------
Plan hash value: 2224805646
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 45 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_TEST3_ID | 71947 | 45 (0)| 00:00:01 |
------------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
167 consistent gets
0 physical reads
0 redo size
345 bytes sent via SQL*Net to client
392 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
--添加hint,強制走index full scan
SQL> select /*+ index(test3 idx_test3_id) */ count(*) from test3;
執行計劃
----------------------------------------------------------
Plan hash value: 2484012340
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 160 (0)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FULL SCAN| IDX_TEST3_ID | 71947 | 160 (0)| 00:00:02 |
-------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
160 consistent gets
0 physical reads
0 redo size
345 bytes sent via SQL*Net to client
392 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> spool off
--總結:
--1、按索引順序查詢的一定會走index full scan,因爲他是按照索引的順序single I/O操作來完成的,即一塊一塊的讀取。
--2、輸出結果不需要是有序的則會走index fast full scan,因爲這樣他的效率會更高一些,
oracle是執行的multiple I/O操作來完成的,一次讀取多個數據塊,讀取個數由參數db_file_multiblock_read_count來決定的