日期:2014-05-16  浏览次数:20668 次

深入理解Oracle索引(1):INDEX SKIP SCAN 和 INDEX RANGE SCAN
       ㈠ Index SKIP SCAN
       
       
表有一个复合索引,而在查询中有除了索引中第一列的其他列作为条件,并且优化器模式为CBO,这时候查询计划就有可能使用到SS
       Skip scan会探测出索引前导列的唯一值个数,每个唯一值都会作为常规扫描的入口,在此基础上做一次查找,最后合并这些查询
       例如:表employees (sex, employee_id, address) ,有一个组合索引(sex, employee_id). 
       在索引跳跃的情况下,我们可以逻辑上把他们看成两个索引:
       一个是(男,employee_id),一个是(女,employee_id).
       一个是(男,employee_id),一个是(女,employee_id).
       select * from employees where employee_id=1;
       发出这个查询后,oracle先进入sex为男的入口,查找employee_id=1的条目。再进入sex为女的入口,查找employee_id=1的条目。最后合并两个结果集
       ORACLE官方说,在前导列唯一值较少的情况下,才会用到index skip can。这个其实好理解,就是入口要少,这也是skip scan的条件
       ORACLE也承认skip scan没有直接索引查询快,但可以这样说,相比于整个表扫描(table scan),索引跳跃式扫描的速度要快得多
       在Oracle9i版本之前,当SQL查询中包含sex和employee_id时,或者查询指定sex的时候才可以使用这一索引,下面的查询就不能使用索引:
       select employee_id from employees where employee_id=7788;
       Oracle9i的索引跳跃式扫描执行规则允许使用连接索引,即使SQL查询中不指定性别
       这一特性使得无需在employee_id行中提供第二个索引
       索引跳跃式扫描适用于硬盘空间和存储空间相当紧缺的情况
       因为一个索引可以满足两个查询条件的使用,比单独建两个索引自然节约了空间

       例如:

hr@ORCL> desc t
 Name                                                  Null?    Type
 ----------------------------------------------------- -------- ------------------------------------
 EMPNO                                                 NOT NULL NUMBER
 SEX                                                   NOT NULL VARCHAR2(4)
 ENAME                                                          VARCHAR2(4)

hr@ORCL> create index sex_empno on t (sex,empno);

Index created.

hr@ORCL> analyze index sex_empno compute statistics;

Index analyzed.

hr@ORCL> select /*+ index_ss(t) */ empno from t where empno=8;

Execution Plan
----------------------
Plan hash value: 3008009344

------------------------------------------
| Id  | Operation        | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------
|   0 | SELECT STATEMENT |           |     1 |    10 |     3   (0)| 00:00:01 |
|*  1 |  INDEX SKIP SCAN | SEX_EMPNO |     1 |    10 |     3   (0)| 00:00:01 |
------------------------------------------


       先看个图:

     

       假如我现在要查找employee_id是109的记录,从图可以看出来,109的记录存在与块3和块5上
       但是skip scan是通过什么样的方式定位到这两个块呢?
       ORACLE可以在SKIP SCAN中,选择相应的入口后,通过根节点和分支节点的信息,非常精准的定位到记录的叶子块,即块3和块5.
       如果要查找employee_id为109的条目,ORACLE进入到入口M后,直接就可以定位到块3.而不需要扫描块1和块2.
       进入到入口F后,直接就可以定位到块5,而不需要扫描块4和块6
       那么,我们上面这条查询,经过skip scan后,内部可能是:
       select empno from t where sex='M' and empno=8
       union
       select empno from t where sex='F' and empno=8;
       我们可以想象,如果索引前导列的唯一值很多,那么势必会大大削弱skip scan的效能,因为可能存在很多union
       有时候为了避免index skip scan,建立新的索引是有必要的