INDEX SKIP SCAN:跳跃式索引可以经过使用非前缀列提升索引的查询性能.一般状况下,扫描索引块比扫描表数据块快.
跳跃式索引可以使复合索引逻辑上拆分分一个个小的子索引.在跳跃式扫描中,复合索引的首列不会被限定在查询中,由于它是跳跃式的.
数据库肯定了必定数量的逻辑子索引经过在首列的去重的值中.当数据库中复合索引的前导列有不多的去重的值和索引中有非前导列有不少重复的值时跳跃式扫描就会有不少优势.
当复合索引的前导列没有被查询谓词界定时,数据库会选择跳跃式索引.web
INDEX FULL SCAN:索引全扫描会排除排序操做,由于数据已经被按索引键值排序.读数据块是逐个读的.数据库在以下任何一个状况时可能会使用full scan:
An ORDER BY clause that meets the following requirements is present in the query(有order by子句存在于查询中):
All of the columns in the ORDER BY clause must be in the index.(在order by中的全部列必须被索引)
The order of the columns in the ORDER BY clause must match the order of the leading index columns.(在order by子句中排序的列必须匹配排序的前导列)
The ORDER BY clause can contain all of the columns in the index or a subset of the columns in the index.(order by子句中包含在索引中的全部列或者索引列的一个子集)
数据库
举例:缓存
SESSION1:
SQL> create table emp5 as select * from emp;
Table created.
SQL> create index skip1 on emp5(job,empno);
Index created.
SQL> commit;
Commit complete.
SQL> set autotrace traceon exp stat;
SQL> select count(*) from emp5 where empno=7900;
Execution Plan
----------------------------------------------------------
Plan hash value: 853491148
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
|* 2 | INDEX FULL SCAN| SKIP1 | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7900)
filter("EMPNO"=7900)
Note
-----
- dynamic sampling used for this statement (level=2) -------此处为动态信息采集,由于表没有被分析.
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
526 bytes sent via SQL*Net to client
523 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.
----------此时再开一个session2,执行以下的查询:
SESSION2:
SQL> set autotrace traceon exp stat;
SQL> set serveroutput on
SQL> select /*+ index_ss(emp5 skip1) */ count(*) from emp5 where empno=7900;-----此处加hint强制走index skip scan,和上面的index full scan造成对比
Execution Plan
----------------------------------------------------------
Plan hash value: 3156092949
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
|* 2 | INDEX SKIP SCAN| SKIP1 | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7900)
filter("EMPNO"=7900)
Note
-----
- dynamic sampling used for this statement (level=2) -----由于表没有被分析,索引此处也是动态信息采集
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
-------此时看不出具体的区别,由于表很小,而且已经被缓存到SGA中.在session2中再执行如下操做:
SQL> alter system flush buffer_cache;
System altered.
SQL> alter system flush shared_pool;
System altered.
SQL> select /*+ index_ss(emp5 skip1) */ count(*) from emp5 where empno=7900;
Execution Plan
----------------------------------------------------------
Plan hash value: 3156092949
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
|* 2 | INDEX SKIP SCAN| SKIP1 | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7900)
filter("EMPNO"=7900)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
62 recursive calls
0 db block gets
56 consistent gets
15 physical reads
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1 rows processed
-------在SESSION1也执行如下操做,确保不受缓存的影响:
SQL> alter system flush buffer_cache;
System altered.
SQL> alter system flush shared_pool;
System altered.
SQL> select count(*) from emp5 where empno=7900;
Execution Plan
----------------------------------------------------------
Plan hash value: 853491148
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
|* 2 | INDEX FULL SCAN| SKIP1 | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7900)
filter("EMPNO"=7900)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
62 recursive calls
0 db block gets
56 consistent gets
17 physical reads ----------------此时能够看出微小的区别,即跳跃式索引产生的物理读比索引全扫描产生的物理读小.
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1 rows processed
----------在SESSION1中分析这个表,再次看分析后的执行计划:
SQL> analyze table emp5 compute statistics;
Table analyzed.
SQL> alter system flush shared_pool;
System altered.
SQL> alter system flush buffer_cache;
System altered.
SQL> select count(*) from emp5 where empno=7900;
Execution Plan
----------------------------------------------------------
Plan hash value: 3156092949
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | INDEX SKIP SCAN| SKIP1 | 1 | 3 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7900)
filter("EMPNO"=7900)
Statistics
----------------------------------------------------------
27 recursive calls
0 db block gets
50 consistent gets
15 physical reads
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1 rows processed
-------------可见分析事后,对于复合索引SKIP1,前导列没有在where的条件下的状况,数据库会自动选择INDEX SKIP SCAN.
-------------在SESSION2中,执行如下操做,看具体区别:
SQL> alter system flush buffer_cache;
System altered.
SQL> alter system flush shared_pool;
System altered.
SQL> select /*+ index_ss(emp5 skip1) */ count(*) from emp5 where empno=7900;
Execution Plan
----------------------------------------------------------
Plan hash value: 3156092949
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | INDEX SKIP SCAN| SKIP1 | 1 | 3 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7900)
filter("EMPNO"=7900)
Statistics
----------------------------------------------------------
27 recursive calls
0 db block gets
50 consistent gets
11 physical reads -------------------此处少了一些,应该是缓存的游标或者在LRU的热端,致使少了一些物理读
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1 rows processed
总结:最好把表分析事后,刷新缓存,这样作实验才有意义.若是走动态采样,能够执行hint看区别.
索引跳跃式扫描能够容许优化器使用组合索引,即使索引的前导列没有出如今WHERE子句中。索引跳跃式扫描比全索引扫描要快的多session