【正确答案】Oracle数据库中最普通、最为常用的即为堆表,堆表的数据存储方式为无序存储,当对数据进行检索的时候,非常消耗资源,这个时候就可以为表创建索引了。在索引中,数据是按照一定的顺序排列起来的。当新建或重建索引时,索引列上的顺序是有序的,而表上的顺序是无序的,这样就存在了差异,即表现为聚簇因子(Clustering Factor,简称CF),也称为群集因子或集群因子等,本书统一称为聚簇因子。聚簇因子值的大小对CBO判断是否选择相关的索引起着至关重要的作用。
在Oracle数据库中,聚簇因子是指按照索引键值排序的索引行和存储于对应表中数据行的存储顺序的相似程度,也就是说,表中数据的存储顺序和某些索引字段顺序的符合程度。CF是基于表上索引列上的一个值,每一个索引都有一个CF值。
Oracle按照索引块所存储的ROwID来标识相邻索引记录在表块中是否为相同块。具体来说,计算CF的算法如下:
1)聚簇因子的初始值为1。
2)Oracle首先定位到目标索引处于最左边的叶子块。
3)从最左边的叶子块的第一个索引键值所在的索引行开始顺序扫描,在顺序扫描的过程中,Oracle会比对当前索引行的ROWID和它之前的那个索引行(它们是相邻的关系)的ROWID,如果这两个ROWID并不是指向同一个表块,那么Oracle就将聚簇因子的当前值递增1;如果这两个ROWID是指向同一个表块,那么Oracle就不改变聚簇因子的当前值。注意,这里Oracle在比对ROWID的时候并不需要回表去访问相应的表块。
4)上述比对ROWID的过程会一直持续下去,直到顺序扫描完目标索引所有叶子块里的所有索引行。
5)上述顺序扫描操作完成后,聚簇因子的当前值就是索引统计信息中的CLUSTERING_FACTOR,Oracle会将其存储在数据字典里。
好的CF值接近于表上的块数,而差的CF值则接近于表上的行数。CF值越小,相似度越高,CF值越大,相似度越低。如果CF的值接近块数,那么说明表的存储和索引存储排序接近,也就是说表中的记录很有序,这样在做INDEX RANGE SCAN的时候,读取少量的数据块就能得到想要的数据,代价比较小。如果CF值接近表记录数,那么说明表的存储和索引排序差异很大,在做INDEX RANGE SCAN的时候,由于表记录分散,所以会额外读取多个块,代价较高。
CF值可以通过查询视图DBA_INDEXES中的CLUSTERJNG_FACTOR列来获取。通过视图DBA_INDEXES、DBA_OBJECTS和DBA_TABLES关联可以得到索引的相关信息,包括当前索引的大小、行数、创建日期、索引高度和聚簇因子等信息。
由于聚簇因子高的索引走索引范围扫描时比相同条件下聚簇因子低的索引要耗费更多的物理I/O,所以聚簇因子高的索引走索引范围扫描的成本会比相同条件下聚簇因子低的索引走索引范围扫描的成本高。Oracle选择索引范围扫描的成本可以近似看作是和聚簇因子成正比,因此,聚簇因子值的大小实际上对CBO判断是否走相关的索引起着至关重要的作用。其实,聚簇因子决定着索引回表读的开销。在Oracle数据库中,能够降低目标索引的聚簇因子的唯一方法就是对表中数据按照目标索引的索引键值排序后重新存储。需要注意的是,这种方法可能会同时增加该表上存在的其他索引的聚簇因子的值。
可以通过如下的命令显式的设置聚簇因子的值:
