索引统计信息中需要我们最为重点关注的是CLUSTERING_FACTOR(聚簇因子)。
1.聚簇因子的初始值为1。
2.Oracle首先定位到目标索引处于最左边的叶子块。
3.从最左边的叶子块的第一个索引键值所在的索引行开始顺序扫描,在顺序扫描的过程中,Oracle会比对当前索引行的rowid和它之前的那个索引行(它们是相邻的关系)的rowid,如果这两个rowid并不是指向同一个表块,那么Oracle就将聚簇因子的当前值递增1;如果这两个rowid是指向同一个表块,Oracle就不改变聚簇因子的当前值。注意,这里Oracle在比对rowid时不需要回表去访问相应的表块。
4.上述比对rowid的过程会一直持续下去,直到顺序扫描完目标索引所有叶子块里的所有索引行。
5.上述顺序扫描操作完成后,聚簇因子的当前值就是索引统计信息中的CLUSTERING_FACTOR,Oracle会将其存储在数据字典里。
从上述聚簇因子的算法可以知道,如果聚簇因子的值接近对应表的表块的数量,则说明目标索引索引行和存储于对应表中数据行的存储顺序相似程度非常高。这也就意味着Oracle走索引范围扫描后取得目标rowid再回表去访问对应表块的数据时,相邻的索引行所对应的rowid极有可能处于同一个表块中,即Oracle在通过索引行记录的rowid回表第一次读取对应的表块并将该表块缓存在buffer cache中后,当再通过相邻索引行记录的rowid回表第二次读取对应的表块时,就不需要再产生物理I/O了,因为这次要访问的和上次已经访问过的表块是同一个块,Oracle已经将其缓存在了buffer cache中。而如果聚簇因子的值接近对应表的记录数,则说明目标索引索引行和存储于对应表中数据行的存储顺序和相似程度非常低,这也就意味着Oracle走索引范围扫描取得目标rowid再回表去访问对应表块的数据时,相邻的索引行所对应的rowid极有可能不处于同一个表块中,即Oracle在通过索引行记录的rowid回表第一次去读取对应的表块并将表块缓存在buffer cache中后,当再通过相邻索引行记录的rowid回表第二次读取对应的表块时,还需要再产生物理I/O,因为这次要访问的和上次已经访问过的表块并不是同一个块。
换句话说,聚簇因子高的索引走索引范围扫描时比相同条件下聚簇因子低的索引要耗费更多的物理I/O,所以聚簇因子高的索引走索引范围扫描的成本会比相同条件下聚簇因子低的索引走索引范围扫描的成本高。
这里构造一个非常极端的例子,全索引中没有任何相邻的索引行记录的rowid指向表中相同的数据块:
根据上述聚簇因子的算法,我们可以算出此索引IDX_T1的聚簇因子的值应是20。
linuxidc@MYDB>create table t1 (id number,name char(1200));
?
Table created.
?
linuxidc@MYDB>insert into t1 values(1,'1');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(3,'3');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(5,'5');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(7,'7');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(9,'9');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(11,'11');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(13,'13');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(15,'15');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(17,'17');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(19,'19');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(2,'2');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(4,'4');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(6,'6');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(8,'8');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(10,'10');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(12,'12');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(14,'14');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(16,'16');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(18,'18');
?
1 row created.
?
linuxidc@MYDB>insert into t1 values(20,'20');
?
1 row created.
?
linuxidc@MYDB>commit;
?
Commit complete.
?
linuxidc@MYDB>create index idx_t1 on t1(id);
?
Index created.
?
linuxidc@MYDB>col location for a10
linuxidc@MYDB>select id,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from t1 order by location,id;
?
? ? ? ? ID LOCATION
---------- ----------
? ? ? ? 1 4_300
? ? ? ? 3 4_300
? ? ? ? 5 4_300
? ? ? ? 7 4_300
? ? ? ? 9 4_300
? ? ? ? 11 4_301
? ? ? ? 13 4_301
? ? ? ? 15 4_301
? ? ? ? 17 4_301
? ? ? ? 19 4_301
? ? ? ? 2 4_302
? ? ? ? 4 4_302
? ? ? ? 6 4_302
? ? ? ? 8 4_302
? ? ? ? 10 4_302
? ? ? ? 12 4_303
? ? ? ? 14 4_303
? ? ? ? 16 4_303
? ? ? ? 18 4_303
? ? ? ? 20 4_303
?
20 rows selected.
从上述显示结果可以看出1、3、5、7、9在4号文件的300号数据块内,11、13、15、17、19在4号文件的301号数据块内,2、4、6、8、10在4号文件的第302号数据块内,12、14、16、18、20在4号文件的第303号数据块内。
收集统计信息并查看聚簇因子的值
#收集统计信息并查看聚簇因子的值
linuxidc@MYDB>exec dbms_stats.gathe