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

index skip scan的一些实验。

index skip scan的基本介绍。

表employees (sex, employee_id, address) ,有一个组合索引(sex, 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。这个其实好理解,就是入口要少。


事实上.jpg

看上面的这幅图。
我有个疑问,就是ORACLE是通过什么样的扫描方式找到所需要的块的,假如我现在要查找employee_id是109的记录,从图可以看出来,109的记录存在与块3和块5上。但是ORACLE能通过skip scan定位到这两个块呢?几种可能。


1)先找到入口M,然后从第一个块扫起,扫到第三个块的时候发现了109,停止扫描。然后找到入口F,从块4扫起,扫描到块5的时候发现了109,由于索引已经是有序的了,后面的不用再扫了。
2)先找到入口M,然后把包含M的块都扫描一下,过滤出109的记录。找到入口F,然后把包含F的块都扫描一下,过滤出109的记录
3)通过根节点和分支节点的信息,非常精准的一下子定位到这两个块上。
到底是那一种呢?

看下面的实验
SQL> create table wxh_tbd as select * from dba_objects;

表已创建。

SQL> update wxh_tbd set object_id=1 where object_id in
??2??(select object_id from (select min(object_id) object_id ,owner from wxh_tbd group by owner));

已更新18行。
SQL> commit;
提交完成。
SQL> update wxh_tbd set object_id=100000000 where object_id in
??2? ?(select object_id from (select max(object_id) object_id ,owner from wxh_tbd group by owner));

已更新18行。
SQL> commit;
SQL> create index t on wxh_tbd(owner,object_id);
索引已创建。

我 的这个测试库里一共有18个schema,通过上面的步骤,我们做到了每个schema下面有一个最小的object_id 即1,一个最大的object_id即100000000.通过以下两个语句的逻辑读我们就可以知道,ORACLE到底是通过三种方式里的哪种来定位块 了。
select /*+ index_ffs(wxh_tbd) */ count(*) from wxh_tbd where object_id=1;
select count(*) from wxh_tbd where object_id=1;
select count(*) from wxh_tbd where object_id=100000000;

实验1)看看如果是采用的index fast scan大概需要多少逻辑读。(这种情况下的逻辑读与上面提到的方法三应该差别不大)
SQL> set autotrace trace stat
SQL> select /*+ index_ffs(wxh_tbd) */ count(*) from wxh_tbd where object_id=1;


统计信息
----------------------
? ?? ?? ? 0??recursive calls
? ?? ?? ? 0??db block gets
? ?? ???156??consistent gets


实验2)object_id为1的时候SQL> select count(*) from wxh_tbd where object_id=1;

执行计划
----------------------
Plan hash value: 2915554405

-------------------------------------
| Id??| Operation? ?? ???| Name | Rows??| Bytes | Cost (%CPU)| Time? ???|
-------------------------------------
|? ?0 | SELECT STATEMENT |? ?? ?|? ???1 |? ???5 |? ? 19? ?(0)| 00:00:01 |
|? ?1 |??SORT AGGREGATE??|? ?? ?|? ???1 |? ???5 |? ?? ?? ?? ?|? ?? ?? ? |
|*??2 |? ?INDEX SKIP SCAN| T? ? |? ???1 |? ???5 |? ? 19? ?(0)| 00:00:01 |
-------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

? ?2 - access("OBJECT_ID"=1)
? ?? ? filter("OBJECT_ID"=1)


统计信息
----------------------
? ?? ?? ? 0??recursive calls
? ?? ?? ? 0??db block gets
? ?? ?? ?14??consistent gets


实验3)看看object_id为100000000的时候的逻辑读。

SQL> select count(*) from wxh_tbd where object_id=100000000;