索引跳跃式扫描(INDEX SKIP SCAN)适用于全部类型的复合B树索引(包括惟一性索引和非惟一性索引),它使那些在where条件中没有对目标索引的前导列指定查询条件但同时又对该 索引的非前导列指定了查询条件的目标SQL依然能够用上该索引,这就像是在扫描该索引时跳过了它的前导列,直接从该索引的非前导列开始扫描同样(实际的执行过程并不是如此),这也是索引跳跃式扫描中"跳跃"(SKIP)一词的含义。sql
为何在where条件中没有对目标索引的前导列指定查询条件但Oracle依然能够用上该索引呢?这是由于Oracle帮你对该索引的前导列的全部distinct值作了遍历。oop
建立一个测试表EMPLOYEE:测试
create table employee(gender varchar2(1),employee_id number);
将该表的列EMPLOYEE_ID的属性设为NOT NULL:spa
alter table employee modify(employee_id not null);
建立一个名为IDX_EMPOLYEE的复合B树索引,其中列GENDER是该索引的前导列,列EMPLOYEE_ID是该索引的第二列:code
create index idx_employee on employee(gender,employee_id);
使用以下PL/SQL代码往表EMPLOYEE中插入10,000条记录,其中5,000条记录的列GENDER的值为"F",另外5,000条记录的列GENDER的值为"M":htm
begin for i in 1..5000 loop insert into employee values ('F',i); end loop; commit; end; begin for i in 5001..10000 loop insert into employee values ('M',i); end loop; commit; end;
analyze table EMPLOYEE compute statistics for table for all columns for all indexes;
执行如下sqlblog
select * from employee where employee_id = 100;
where条件是"employee_id = 100",即它只对复合B树索引IDX_EMPOLYEE的第二列EMPLOYEE_ID指定了查询条件,但并无对该索引的前导列GENDER指定任何查询条件。索引
set autotrace traceonly select * from employee where employee_id = 100;
执行计划以下:ip
从上述显示内容能够看出,Oracle在执行时用上了索引IDX_EMPOLYEE,而且其执行计划走的就是对该索引的索引跳跃式扫描。get
这里在没有指定前导列的状况下还能用上述索引,就是由于Oracle帮咱们对该索引的前导列的全部distinct值作了遍历。
所谓的对目标索引的全部distinct值作遍历,其实际含义至关于对原目标SQL作等价改写(即把要用的目标索引的全部前导列的distinct 值都加进来)。索引IDX_EMPOLYEE的前导列GENDER的distinct值只有"F"和"M"两个值,因此这里能使用索引 IDX_EMPOLYEE的缘由能够简单地理解成是Oracle将范例SQL 9等价改写成了以下形式:
select * from employee where gender = 'F' and employee_id = 100 union all select * from employee where gender = 'M' and employee_id = 100;
Oracle中的索引跳跃式扫描仅仅适用于那些目标索引前导列的distinct值数量较少、后续非前导列的可选择性又很是好的情形,由于索引跳跃式扫描的执行效率必定会随着目标索引前导列的distinct值数量的递增而递减。