索引跳跃式扫描
当一个查询未在where子句的谓词中指定复合索引的前导列,查询“跳过”该列时,就会发生索引跳跃式扫描。数据库将一个复合索引拆分成多个逻辑子索引。复合索引前导列中的不同值越少,组成复合索引的其他键的不同值越多,索引跳跃式扫描的性能就越好。例如,如果前导列有三个不同值,数据库将把复合索引拆分成三个逻辑子索引,并在其中搜索索引非前导列的值。
在下面的例子中,数据库使用了复合索引test_i1,它是在列(b,c)上创建的。查询指定的条件是”c<10″。查询的where子句没有使用复合索引的前导列(b),从而跳过该列。
SQL> select * from test where c<10; A B C ---------- ---------- ---------- 0 F 1 0 F 2 0 F 3 0 F 4 0 F 5 0 F 6 0 F 7 0 F 8 0 F 9 9 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 650436733 ----------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9 | 90 | 1 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TEST | 9 | 90 | 1 (0)| 00:00:01 | |* 2 | INDEX SKIP SCAN | TEST_I1 | 9 | | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("C"<10) filter("C"<10)
数据库把复合索引拆分成多少逻辑子索引,取决于前导列的不同值数量。在这个例子中,复合索引的前导列b只有极少数不同的值:
SQL> select distinct b from test; B ---------- M F
正如输出结果所显示的,复合索引的前导列只有两个不同的值。数据库把复合索引(b,c)拆分成两个子索引,第一个子索引的键值是”M”,而第二个子索引的键值是”2″。数据库检索第一个子索引,然后检索第二个子索引。另外,索引的非前导列c有200000个不同的值(与表中的行数据相同)。在这样的情况下,由于复合索引前导列中的不同值很少,数据库将采用复合索引跳跃式扫描,而不是像在以前版本的数据库(也就是说,Oracle 9i以前的版本)中那样执行全表扫描。