为什么index fast full scan会扫描segment header,index full scan 不扫描 segment header

index full scan , 扫描root block ---> branch block ----> leaf block ,扫描leaf block的时候是有序的,可以从左往右,也可以从右往左,返回的结果也是有序的,并且是但块读

index fast full scan 扫描 索引段头(单块读) --->root block---->branch block----->leaf block

 

下面来做个实验(基于Oracle10g,段自动管理)

create table test as select * from dba_objects;

alter table test modify owner not null;

create index idx_owner on test(owner);

 

select /*+ index(test idx_owner) */ owner from test where rownum<1001;       ----它会走 index full scan

select /*+ index_ffs(test idx_owner) */ owner from test where rownum<1001;  ----它会走 index fast full scan

 

对 index full scan 的SQL 进行10046跟踪,跟踪的时候记得设置下面参数

set arraysize 1000;
alter system flush buffer_cache; ----一定要刷新,不然观察不到 db file sequential read
alter system flush shared_pool;
alter session set events '10046 trace name context forever, level 8';

select /*+ index(test idx_owner) */ owner from test where rownum<1001; 

alter session set events '10046 trace name context off';

找到10046 trace 文件

=====================
PARSING IN CURSOR #1 len=69 dep=0 uid=54 oct=3 lid=54 tim=271045223908 hv=4111226343 ad='1c118ecc'
select /*+ index(test idx_owner) */ owner from test where rownum<1001
END OF STMT
PARSE #1:c=78001,e=192236,p=26,cr=165,cu=0,mis=1,r=0,dep=0,og=1,tim=271045223905
EXEC #1:c=0,e=14,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=271045224086
WAIT #1: nam='SQL*Net message to client' ela= 2 driver id=1111838976 #bytes=1 p3=0 obj#=10234 tim=271045224133
WAIT #1: nam='db file sequential read' ela= 8887 file#=4 block#=3468 blocks=1 obj#=53777 tim=271045233777
WAIT #1: nam='db file sequential read' ela= 277 file#=4 block#=3469 blocks=1 obj#=53777 tim=271045234190
FETCH #1:c=0,e=10124,p=2,cr=2,cu=0,mis=0,r=1,dep=0,og=1,tim=271045234294
WAIT #1: nam='SQL*Net message from client' ela= 324 driver id=1111838976 #bytes=1 p3=0 obj#=53777 tim=271045234689
WAIT #1: nam='SQL*Net message to client' ela= 1 driver id=1111838976 #bytes=1 p3=0 obj#=53777 tim=271045234789
WAIT #1: nam='SQL*Net more data to client' ela= 9 driver id=1111838976 #bytes=2002 p3=0 obj#=53777 tim=271045235017
WAIT #1: nam='db file sequential read' ela= 286 file#=4 block#=3470 blocks=1 obj#=53777 tim=271045235371
WAIT #1: nam='SQL*Net more data to client' ela= 9 driver id=1111838976 #bytes=2000 p3=0 obj#=53777 tim=271045235550
WAIT #1: nam='db file sequential read' ela= 321 file#=4 block#=3471 blocks=1 obj#=53777 tim=271045235939
FETCH #1:c=0,e=1279,p=2,cr=3,cu=0,mis=0,r=999,dep=0,og=1,tim=271045236055
WAIT #1: nam='SQL*Net message from client' ela= 8914715 driver id=1111838976 #bytes=1 p3=0 obj#=53777 tim=271054150848
STAT #1 id=1 cnt=1000 pid=0 pos=1 obj=0 op='COUNT STOPKEY (cr=5 pr=4 pw=0 time=10119 us)'
STAT #1 id=2 cnt=1000 pid=1 pos=1 obj=53777 op='INDEX FULL SCAN IDX_OWNER (cr=5 pr=4 pw=0 time=10116 us)'
=====================


扫描的第一个block是3468,然后3469,3470,3471

SQL> select header_file,header_block from dba_segments where segment_name='IDX_OWNER';

HEADER_FILE HEADER_BLOCK
----------- ------------
          4         3467

SQL> select name,height from index_stats where name='IDX_OWNER';

NAME                               HEIGHT
------------------------------ ----------
IDX_OWNER                               2      

 

这个索引的段头块是3467,root block就是段头+1 ,这里 root block 就是3468 ,根据实验可知,index full scan 没有扫描 segment header ,而是直接扫描 root block

 

再来看 index fast full scan 实验

set arraysize 1000;
alter system flush buffer_cache;
alter system flush shared_pool;
alter session set events '10046 trace name context forever, level 8';

select /*+ index_ffs(test idx_owner) */ owner from test where rownum<1001;

alter session set events '10046 trace name context off';

找到10046 trace文件

=====================
PARSING IN CURSOR #4 len=73 dep=0 uid=54 oct=3 lid=54 tim=272536163194 hv=1795841612 ad='18686370'
select /*+ index_ffs(test idx_owner) */ owner from test where rownum<1001
END OF STMT
PARSE #4:c=46801,e=206181,p=14,cr=55,cu=0,mis=1,r=0,dep=0,og=1,tim=272536163192
EXEC #4:c=0,e=13,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=272536163332
WAIT #4: nam='SQL*Net message to client' ela= 2 driver id=1111838976 #bytes=1 p3=0 obj#=10234 tim=272536163375
WAIT #4: nam='db file sequential read' ela= 8670 file#=4 block#=3467 blocks=1 obj#=53777 tim=272536172783
WAIT #4: nam='db file scattered read' ela= 571 file#=4 block#=3468 blocks=5 obj#=53777 tim=272536173489
FETCH #4:c=15600,e=10219,p=6,cr=7,cu=0,mis=0,r=1,dep=0,og=1,tim=272536173634
WAIT #4: nam='SQL*Net message from client' ela= 255 driver id=1111838976 #bytes=1 p3=0 obj#=53777 tim=272536173968
WAIT #4: nam='SQL*Net message to client' ela= 1 driver id=1111838976 #bytes=1 p3=0 obj#=53777 tim=272536174046
WAIT #4: nam='SQL*Net more data to client' ela= 8 driver id=1111838976 #bytes=2002 p3=0 obj#=53777 tim=272536174209
WAIT #4: nam='SQL*Net more data to client' ela= 6 driver id=1111838976 #bytes=2000 p3=0 obj#=53777 tim=272536174344
FETCH #4:c=0,e=398,p=0,cr=3,cu=0,mis=0,r=999,dep=0,og=1,tim=272536174432
*** 2012-03-02 14:25:15.649
WAIT #4: nam='SQL*Net message from client' ela= 13715652 driver id=1111838976 #bytes=1 p3=0 obj#=53777 tim=272549890151
STAT #4 id=1 cnt=1000 pid=0 pos=1 obj=0 op='COUNT STOPKEY (cr=10 pr=6 pw=0 time=10214 us)'
STAT #4 id=2 cnt=1000 pid=1 pos=1 obj=53777 op='INDEX FAST FULL SCAN IDX_OWNER (cr=10 pr=6 pw=0 time=10209 us)'
=====================


最开始扫描的是3467,它是索引的段头,并且是单块读(注意:段头都是单块读),然后才是从3468 开始扫描,一共扫描了5个block 3468就是索引的root block

这里也知道了,无论哪种索引扫描,都会扫描 root block

 

为什么 index fast full scan 要扫描 segment header呢?因为 index fast full scan 需要扫描所有的索引块(leaf block),并且扫描不是有序的,是多块读,而且它不会回表,也就是说它不会解析出rowid,正是由于它要扫描所有的leaf block,并且是离散读,所以它必须读取segment header,不然oracle怎么知道它读取了所有的 leaf block?

 

为什么 index full scan 不扫描segment header? 因为 index full scan 是连续读的,由于leaf block之间有双向指针,Oracle不需要扫描segment header就能判断 leaf block 扫描完了没,它只需要从左往右,或者从右往左一直扫描到尽头即可。

 

 

posted on 2012-03-02 16:28  如果蜗牛有爱情  阅读(202)  评论(0编辑  收藏  举报

导航