暂无图片
分享
周伟
2019-09-23
关于索引的clustering_factor

请教专家:

关于dba_indexes视图当中的 clustering_factor字段,表示着基表数据与索引之间数据排列顺序的契合程度。按照理解,clustering_factor的大小越接近基表的block数量就表示排序程度越高,索引效率也越高,如果clustering_factor越接近NUM_ROWS 则表示排序程度越低,索引效率也越低。

请教一下,这个地方NUM_ROWS通常在参考的时候,是参考的dba_indexes 里面的NUM_ROWS 字段,还是参考的dba_tables里面的NUM_ROWS字段,或者是实际 select count(*) from table 得到的结果?

因为dba_indexes里面的NUM_ROWS代表的是索引记录行数,假如索引参考的基表列,存在较多的NULL值的话,它是不会记录的,因此存在索引记录的行数和基表的实际行数有较大差距的问题。而dba_tables 里面的NUM_ROWS 通常是在搜集了统计信息之后才会有数据,但假如数据的自动信息搜集功能被关闭了,这个数据是不是会存在更新不及时的现象?

另外,一般参考范围的话,clustering_factor的值大约占 NUM_ROWS是的百分之多少,表示这个索引或者基表可以纳入重建的考虑范围?(重建索引也不会降低CF值。)

收藏
分享
7条回答
默认
最新
章芋文

首先你有几点理解有问题,可以参考dbsnake的描述:

(1) CF初始值是1。 
(2) Oracle首先定为至目标索引最左边的叶子块。 
(3) 从最左边的叶子块的第一个索引键值所在的索引行开始顺序扫描,Oracle比较当前索引行的roid和他之前相邻的索引行的rowid,若这两rowid并不是指向同一个表块,则将聚簇因子值递增1,如果指向同一个rowid,则不改变当前聚簇因子值。比对rowid的时候并不需要回表访问相应的表块。(注:原因就是根据rowid的值是可以计算出block信息) 
(4) 直到顺序扫描完目标索引所有叶子块的所有索引行。 
(5) 扫描操作完成后,聚簇因子当前值就是会被存储在数据字典中,就是上面视图中CLUSTERINGFACTOR列


总结: 

1.聚簇因子表示索引键值的排列顺序和表中数据排列顺序的相似程度。 
2.可以粗略认为索引范围扫描的成本,和聚簇因子的大小成正比,从索引范围扫描的计算方法可以推出这个结论。 
3.是否需要重新组织表中数据存储顺序,以降低某一个索引的聚簇因子值,需要结合实际需求来判断,因为若表中存在多个索引,很可能造成顾此失彼的情况。

暂无图片 评论
暂无图片 有用 0
周伟

@章芋文,谢谢您的回答。你所说的内容我都理解,但是我还是没有搞清楚,怎么去判断一个索引的聚簇因子到底是好还是坏(暂且假如基表只有一个索引的情况),那么这个聚簇因子“是否太大还是太小”就有一个参照的数据进行比对,也就是所谓的去和“NUM_ROWS”进行比对,如果接近NUM_ROWS就表示太高,反之就是良好(较低),我就是想问一下两个核心问题:

  1. dba_indexes视图里面的NUM_ROWS表示的是索引记录行数(排除索引列空值),还是基表的记录行数(包括索引列空值);

  2. 聚簇因子所参照的NUM_ROWS 到底是来自于dba_indexes里面的NUM_ROWS字段,还是dba_tables里面的NUM_ROWS字段,或者是直接select count(*) from table得到的实际值;

暂无图片 评论
暂无图片 有用 0
章芋文

与NUM_ROWS无关,CF的计算如下:

从最左边的叶子块的第一个索引键值所在的索引行开始顺序扫描,Oracle比较当前索引行的rowid和他之前相邻的索引行的rowid,若这两rowid并不是指向同一个表块,则将聚簇因子值递增1,如果指向同一个rowid,则不改变当前聚簇因子值。

image.png

如上图所示,第二种情况的CF=3,可以理解为:CF越大,需要扫描的块越多,CF越小,需要扫描的块越少。如果两个索引的其他统计信息一致,CBO再计算成本是优先选择CF小的。

暂无图片 评论
暂无图片 有用 0
周伟

@章芋文,谢谢。

其实我知道CF是怎么计算的,我之所以不厌其烦的问,其实就是我实际碰到的一个问题,客户问我,“哎?你咋知道这个索引的聚簇因子很高啊?判断的依据是啥?” 。。 我其实就是想搞清楚这个问题。在实际生产的优化手段中,我实际上很少去看这个东西,只是作为一个判断索引效率的参考手段了。

暂无图片 评论
暂无图片 有用 0
章芋文

这确实是一个优化的参考指标,但是往往优化整改的代价很高,因为索引字段都是排序的,而表中的数据本身就是无序的,加上经常有DML操作,数据在块中的分布就更乱了,比如主键ID列,要想重新整理数据,最有效的方式是create table tab_bak as select * from table_org order by id。

在11G之后我们都没有特意去看这个指标了,只是在做个别SQL TUNNING的时候会去查一下这个值。

暂无图片 评论
暂无图片 有用 0
周伟

@章芋文

了解,跟我的想法差不多。谢了!

暂无图片 评论
暂无图片 有用 0
周伟
问题已关闭: 问题已经得到解决
暂无图片 评论
暂无图片 有用 0
回答交流
提交
问题信息
请登录之后查看
邀请回答
暂无人订阅该标签,敬请期待~~
暂无图片墨值悬赏