触发条件:只需要从索引中就可以取出所需要的结果集,此时就会走索引全扫描
Full Index Scan 按照数据的逻辑顺序读取数据块,会发生单块读事件,
Fast Full Index Scan 按照数据块的物理存储位置顺序读取数据块,会发生多块读事件,理论上索引快速全扫描会比索引全扫描要快
官档的解释:
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.
原理:ORACLE定位到索引的ROOT BLOCK,然后到BRANCH BLOCK(如果有的话),再定位到第一个LEAF BLOCK, 然后根据LEAF BLOCK的双向链表顺序读取。它所读取的块都是有顺序的,也是经过排序的。
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.
A fast full scan is faster than a normal full index scan because it can use multiblock I/O and can run in parallel just like a table scan.
The database cannot perform fast full index scans of bitmap indexes.
原理:从段头开始,读取包含位图块,ROOT BLOCK,所有的BRANCH BLOCK,LEAF BLOCK,读取的顺序完全有物理存储位置决定,并采取多块读,每次读取DB_FILE_MULTIBLOCK_READ_COUNT个块。查询某个表记录总数的时候,往往基于PRIMARY KEY的INDEX FAST FULL SCAN是最有效的。
测试COST:
SQL> create table t3 as select * from dba_objects;
表已创建。
SQL> create index t3_ix on t3(object_id);
索引已创建。
SQL> alter table t3 modify(object_id not null);
表已更改。
SQL> exec dbms_stats.gather_table_stats('SYS','T3');
PL/SQL 过程已成功完成。
SQL> set autot on
SQL> select count(*) from t3;
COUNT(*)
----------
72006
执行计划
----------------------------------------------------------
Plan hash value: 271548554
------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | (0)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FULL SCAN| T3_IX | 63127 | 162 (0)| 00:00:02 |
------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
SQL> select count(*) from t3;
COUNT(*)
----------
72006
执行计划
----------------------------------------------------------
Plan hash value: 2285970227
-----------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| T3_IX | 63127 | 62 (0)| 00:00:01 |
-----------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
可以看到,indexl full scan的cost 为162,index fast full scan 的cost 为62,fast full scan的cost明显要低。
测试SORT:
SQL> select object_id from t3 where rownum<10 order by object_id;
OBJECT_ID
----------
2
3
4
5
6
7
8
9
10
已选择9行。
执行计划
----------------------------------------------------------
Plan hash value: 633445068
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 45 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | INDEX FULL SCAN| T3_IX | 9 | 45 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<10)
SQL> select object_id from t3 where rownum<10 order by object_id;
OBJECT_ID
----------
2
3
4
5
6
7
8
9
10
已选择9行。
执行计划
----------------------------------------------------------
Plan hash value: 512512221
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 45 | | 284 (2)| 00:00:04 |
| 1 | SORT ORDER BY | | 9 | 45 | 856K| 284 (2)| 00:00:04 |
|* 2 | COUNT STOPKEY | | | | | | |
| 3 | INDEX FAST FULL SCAN| T3_IX | 72006 | 351K| | 61 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM<10)
通过执行计划可以看到,fast_full_scan多了一个排序的步骤,而full scan没有这个排序的步骤,说明full scan的数据是根据索引键排好序的,而fast_full_scan的多块读导致其没有按照索引键排好序