一个索引跳跃扫描时发生复合索引的初始列是“跳过”或在查询未指定。
8.3.6.1当优化器考虑索引跳过扫描时
通常,跳过扫描索引块比扫描表块快,并且比执行全索引扫描快。
当满足以下条件时,优化器将考虑跳过扫描:
- 在查询谓词中未指定复合索引的前导列。
例如,查询谓词未引用该
cust_gender列,并且复合索引键为(cust_gender,cust_email)。 - 复合索引的前导列中几乎没有不同的值(选择性差),但是索引的非前导键中存在许多不同的值。
例如,如果组合索引键为
(cust_gender,cust_email),则该cust_gender列只有两个不同的值,但cust_email有数千个。
8.3.6.2索引跳过扫描如何工作
索引跳过扫描在逻辑上将组合索引拆分为较小的子索引。
索引的前几列中不同值的数量确定逻辑子索引的数量。数字越小,优化器必须创建的逻辑子索引越少,并且扫描变得越有效。扫描将分别读取每个逻辑索引,并在不超前的列上“跳过”不满足过滤条件的索引块。
8.3.6.3索引跳过扫描:示例
本示例使用索引跳过扫描来满足对sh.customers表的查询。
该customers表包含一列,cust_gender其值为M或F。以用户身份登录数据库后sh,您可以在列(cust_gender, cust_email)上创建一个复合索引,如下所示:
CREATE INDEX cust_gender_email_ix
ON sh.customers (cust_gender, cust_email);
从概念上讲,该索引的一部分可能看起来如下所示,其性别值为F或M作为该索引的前沿。
F,Wolf@company.example.com,rowid
F,Wolsey@company.example.com,rowid
F,Wood@company.example.com,rowid
F,Woodman@company.example.com,rowid
F,Yang@company.example.com,rowid
F,Zimmerman@company.example.com,rowid
M,Abbassi@company.example.com,rowid
M,Abbey@company.example.com,rowid您在sh.customers表中为客户运行以下查询:
SELECT *
FROM sh.customers
WHERE cust_email = 'Abbey@company.example.com';
customers_gender_email即使cust_gender未在WHERE子句中指定,数据库也可以使用索引的跳过扫描。在样本索引中,前导列cust_gender具有两个可能的值:F和M。数据库在逻辑上将索引分为两个。一个子索引具有key F,其条目的格式如下:
F,Wolf@company.example.com,rowid
F,Wolsey@company.example.com,rowid
F,Wood@company.example.com,rowid
F,Woodman@company.example.com,rowid
F,Yang@company.example.com,rowid
F,Zimmerman@company.example.com,rowid
第二个子索引具有key M,其条目具有以下形式:
M,Abbassi@company.example.com,rowid
M,Abbey@company.example.com,rowid
在搜索电子邮件地址为客户的记录时Abbey@company.example.com,数据库首先搜索具有前导值F的子索引,然后搜索具有前导值的子索引M。从概念上讲,数据库按以下方式处理查询:
( SELECT *
FROM sh.customers
WHERE cust_gender = 'F'
AND cust_email = 'Abbey@company.example.com' )
UNION ALL
( SELECT *
FROM sh.customers
WHERE cust_gender = 'M'
AND cust_email = 'Abbey@company.example.com' )
查询计划如下:
SQL_ID d7a6xurcnx2dj, child number 0
-------------------------------------
SELECT * FROM sh.customers WHERE cust_email = 'Abbey@company.example.com'
Plan hash value: 797907791
-----------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)|Time|
-----------------------------------------------------------------------------------------
| 0|SELECT STATEMENT | | | |10(100)| |
| 1| TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS |33|6237| 10(0)|00:00:01|
|*2| INDEX SKIP SCAN | CUST_GENDER_EMAIL_IX |33| | 4(0)|00:00:01|
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("CUST_EMAIL"='Abbey@company.example.com')
filter("CUST_EMAIL"='Abbey@company.example.com')



