版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载。转载时,请在文章明显位置注明原文链接。若在未经作者同意的情况下,将本文内容用于商业用途,将保留追究其法律责任的权利。如果有问题,请以邮箱方式联系作者(793113046@qq.com)。


1、聚簇因子的概念

  • 聚簇因子,是CBO优化器决定是否使用索引的因素之一,主要反映索引块上的数据(顺序存储),与该索引基于的表块上的数据(无序存储)的顺序相似程度的差异性。即表数据的存储顺序是否与相应索引数据的存储顺序一致。
  • 通过查询dba_indexes视图、user_indexes视图以及all_indexes视图的CLUSTERING_FACTOR列,可以了解当前索引的聚簇因子值。

2、索引块与相应数据块之间数据分布产生差异的原因

  • 对于索引块的数据存储,这里以普通btree索引为例,索引块中键值的分布总是有序的,且根据键值及其相应的rowid信息,唯一定位一行记录在相应表的数据块中的分布。理想情况下,相同或相邻的键值,尽量定位在相同的数据块上,可以避免对于数据块多余的I/O操作。

  • 对于数据块的数据存储,并不是有序存储的。且ORACLE为节省空间,会优先使用当前当水位线(HWM)以下的可用数据块,而不是按序使用最后被使用的块。当HWM以下无可用数据块时,再开辟新的数据块使用。
  • 正因为数据块中数据存储的特点,随着时间的推移,数据在相应数据块间的分布越发零散,进而影响索引块中,相同或相邻键值对应的相应数据行信息(rowid),所指向的数据块越加分散,进而导致聚簇因子变差。

3、聚簇因子的计算方法

聚簇因子大致的计算方法顺序如下:

  1. 进行一次索引全扫描
  2. 检查索引块中的rowid信息。比较前一个rowid与一个rowid是否指向同一个数据块。若不同,则聚簇因子加1.
  3. 当完成整个的索引扫面后,即得到该索引的聚簇因子的数值。

4、聚簇因子好坏的判断

良好的CF值,会趋向于数据表的块数。

较差的CF值,会趋向于数据表的行数。

需要注意的是:随着时间的推移,频繁的DML操作,会让CF值总是趋向于恶劣方向发展。

示例:

本示例主要说明CF的趋势性。

--查看当前测试表中索引的聚簇因子情况
--注意此时的LAST_ANALYZED为空,说明未收集过统计信息
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR,
2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows,
3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED
4 from dba_segments a,dba_indexes b ,dba_tables c
5 where a.segment_name=b.table_name
6 and a.segment_name=c.table_name
7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED
--------------- --------------- ----------------- ---------- ---------- -------------------
TEST_IDX TEST 17381 18432 1217342 --分析收集表test最新的统计信息
Yumiko_sunny@OA01> analyze table test compute statistics;
Table analyzed. --查看收集后最新的信息,可以看到,结果集中CF值,明显小于数据块值,说明此时情况相似度很好。
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR,
2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows,
3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED
4 from dba_segments a,dba_indexes b ,dba_tables c
5 where a.segment_name=b.table_name
6 and a.segment_name=c.table_name
7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED
--------------- --------------- ----------------- ---------- ---------- -------------------
TEST_IDX TEST 17381 18432 1217342 2016-11-06 16:38:08 --插入新的数据并进行提交
Yumiko_sunny@OA01> insert into test select * from test;
1217342 rows created. Yumiko_sunny@OA01> commit;
Commit complete. --再次收集表test相关的统计信息
Yumiko_sunny@OA01> analyze table test compute statistics;
Table analyzed. --不难发现,随着insert的操作,CF值发生了改变,虽然目前该值在可接受范围内,但已经开始趋向行数。
--可以想象下,一个生产环境中,除了insert,还有update跟delete,随着这些操作的增多,势必更加趋向行数。
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR,
2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows,
3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED
4 from dba_segments a,dba_indexes b ,dba_tables c
5 where a.segment_name=b.table_name
6 and a.segment_name=c.table_name
7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED
--------------- --------------- ----------------- ---------- ---------- -------------------
TEST_IDX TEST 206123 35840 2016-11-06 16:39:58

5、聚簇因子的优化

由于影响CF(CLUSTERING_FACTOR)值的主要取决于数据表的数据,在数据块中的存储分布情况,因此优化CF的重点还是在调整数据表本身,具体方法如下:

  • 定期按索引列顺序重建表

    • 建议通过dbms_metadata.get_ddl提取表结构完整的DDL语句,结合insert order by column以及rename table的方式进行表的重建。
    • 不建议采用CTAS方式(create table as select),该方式可能引起后续不必要的麻烦。具体影响可参阅链接中的案例 http://blog.csdn.net/leshami/article/details/7362156
  • 使用聚簇表代替普通的数据表

    • 频繁DML的表以及经常需要全表扫描的表,不适合建立聚簇表。
    • 具体查阅作者前面关于“表簇索引”一文的介绍 “Oracle索引种类之表簇索引(cluster index)”

示例:

本示例承接上面的示例,主要演示通过重建表的方式进行聚簇因子优化的过程。

--再次确认原始表test的CF值
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR,
2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows,
3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED
4 from dba_segments a,dba_indexes b ,dba_tables c
5 where a.segment_name=b.table_name
6 and a.segment_name=c.table_name
7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED
--------------- --------------- ----------------- ---------- ---------- -------------------
TEST_IDX TEST 35840 2434684 2016-11-06 22:10:51 --通过调用dbms_metadata包的get_ddl函数,抽取原始表test的DDL结构语句
Yumiko_sunny@OA01> set long 100000
Yumiko_sunny@OA01> set pages 0
Yumiko_sunny@OA01> select dbms_metadata.get_ddl('TABLE',upper('&table_name'),upper('&owner')) from dual;
Enter value for table_name: TEST
Enter value for owner: SCOTT
old 1: select dbms_metadata.get_ddl('TABLE',upper('&table_name'),upper('&owner')) from dual
new 1: select dbms_metadata.get_ddl('TABLE',upper('TEST'),upper('SCOTT')) from dual CREATE TABLE "SCOTT"."TEST"
( "OWNER" VARCHAR2(30),
"OBJECT_NAME" VARCHAR2(128),
"SUBOBJECT_NAME" VARCHAR2(30),
"OBJECT_ID" NUMBER,
"DATA_OBJECT_ID" NUMBER,
"OBJECT_TYPE" VARCHAR2(19),
"CREATED" DATE,
"LAST_DDL_TIME" DATE,
"TIMESTAMP" VARCHAR2(19),
"STATUS" VARCHAR2(7),
"TEMPORARY" VARCHAR2(1),
"GENERATED" VARCHAR2(1),
"SECONDARY" VARCHAR2(1),
"NAMESPACE" NUMBER,
"EDITION_NAME" VARCHAR2(30)
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" --利用抽取的原始表test的结构语句,创建新表test_tmp
Yumiko_sunny@OA01> CREATE TABLE "SCOTT"."TEST_TMP"
2 ( "OWNER" VARCHAR2(30),
3 "OBJECT_NAME" VARCHAR2(128),
4 "SUBOBJECT_NAME" VARCHAR2(30),
5 "OBJECT_ID" NUMBER,
6 "DATA_OBJECT_ID" NUMBER,
7 "OBJECT_TYPE" VARCHAR2(19),
8 "CREATED" DATE,
9 "LAST_DDL_TIME" DATE,
10 "TIMESTAMP" VARCHAR2(19),
11 "STATUS" VARCHAR2(7),
12 "TEMPORARY" VARCHAR2(1),
13 "GENERATED" VARCHAR2(1),
14 "SECONDARY" VARCHAR2(1),
15 "NAMESPACE" NUMBER,
16 "EDITION_NAME" VARCHAR2(30)
17 ) SEGMENT CREATION IMMEDIATE
18 PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
19 NOCOMPRESS LOGGING
20 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
21 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
22 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
23 TABLESPACE "USERS"; Table created. --通过对原始表test的索引列进行order by排序操作后,差入到新表test_tmp中
--通过append hint的方法,虽然可以减少redo的产生,并且在hwm以上开辟数据块,加快了数据的加载速度。
--但该方式,在commit或者rollback事物前,其他会话无法针对该表进行DML操作,生产环境中需要注意。
Yumiko_sunny@OA01> insert into /*+append */ test_tmp select * from test order by object_id;
2434684 rows created. Yumiko_sunny@OA01> commit; --为新表test_tmp的索引列添加索引
Yumiko_sunny@OA01> create index test_idx_new on test_tmp(object_id);
Index created. --将原始表test进行重命名test_old
Yumiko_sunny@OA01> alter table test rename to test_old;
Table altered. --将新表test_tmp重命名为test
Yumiko_sunny@OA01> alter table test_tmp rename to test;
Table altered. --分析收集新表test的统计信息
Yumiko_sunny@OA01> analyze table TEST compute statistics;
Table analyzed. --查看新建的表test的CF,不难发现,此时的CF值将较之前已经明显下降。
--至此,CF的优化过程结束。
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR,
2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows,
3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED
4 from dba_segments a,dba_indexes b ,dba_tables c
5 where a.segment_name=b.table_name
6 and a.segment_name=c.table_name
7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED
----------------------------------------------------------------------------------------
TEST_IDX_NEW TEST 39700 35840 2434684 2016-11-06 22:26:10

需要补充说明的是:
对于alter table move的操作,可以降低高水位线,但对于优化聚簇因子值而言,意义不大。
对于重建索引,通过实验发现(只进行了两个实验,可能结果集存在误差),聚簇因子值不但未降低,有时还存在些许的增加,需要注意。

Oracle索引梳理系列(九)- 浅谈聚簇因子对索引使用的影响及优化方法的更多相关文章

  1. [独孤九剑]Oracle知识点梳理(九)数据库常用对象之package

    本系列链接导航: [独孤九剑]Oracle知识点梳理(一)表空间.用户 [独孤九剑]Oracle知识点梳理(二)数据库的连接 [独孤九剑]Oracle知识点梳理(三)导入.导出 [独孤九剑]Oracl ...

  2. 【公众号系列】浅谈SAP项目管理的技能

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[[公众号系列]浅谈SAP项目管理的技能   写 ...

  3. 【ASP.NET MVC系列】浅谈数据注解和验证

    [ASP.NET MVC系列]浅谈数据注解和验证   [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google C ...

  4. 【Fiori系列】浅谈SAP Fiori的设计美感与发展历程

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[Fiori系列]浅谈SAP Fiori的设计美 ...

  5. Spring5.0源码学习系列之浅谈BeanFactory创建

    Spring5.0源码学习系列之浅谈BeanFactory创建过程 系列文章目录 提示:Spring源码学习专栏链接 @ 目录 系列文章目录 博客前言介绍 一.获取BeanFactory主流程 二.r ...

  6. 浅谈分词算法(5)基于字的分词方法(bi-LSTM)

    目录 前言 目录 循环神经网络 基于LSTM的分词 Embedding 数据预处理 模型 如何添加用户词典 前言 很早便规划的浅谈分词算法,总共分为了五个部分,想聊聊自己在各种场景中使用到的分词方法做 ...

  7. 浅谈分词算法(4)基于字的分词方法(CRF)

    目录 前言 目录 条件随机场(conditional random field CRF) 核心点 线性链条件随机场 简化形式 CRF分词 CRF VS HMM 代码实现 训练代码 实验结果 参考文献 ...

  8. 浅谈分词算法(3)基于字的分词方法(HMM)

    目录 前言 目录 隐马尔可夫模型(Hidden Markov Model,HMM) HMM分词 两个假设 Viterbi算法 代码实现 实现效果 完整代码 参考文献 前言 在浅谈分词算法(1)分词中的 ...

  9. Oracle索引梳理系列(五)- Oracle索引种类之表簇索引(cluster index)

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

随机推荐

  1. ABP源码分析六:依赖注入的实现

    ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...

  2. Java访问Hbase

    1.kerberos验证 a.下载对应版本JCE(Java Cryptography Extension),解压拷贝local_policy.jar/US_export_policy.jar到$JAV ...

  3. Android-Eclipse-INSTALL_FAILED_UPDATE_INCOMPATIBLE错误

    电脑重装了系统,环境问题一大堆,唉,搞死人,这不,今天就出现了这样的一个奇怪的问题. INSTALL_FAILED_UPDATE_INCOMPATIBLE 最后搜了一遍,发现是因为已经安装了这个包,包 ...

  4. 升级xcode8 之后遇到的一些问题

    昨天趁着快下班,就将xcode升级为8了,运行起来并没有什么问题,今天一早过来运行,结果,模拟器打不开了.... 1. unable to boot the Simulator 解决办法:重启Mac时 ...

  5. Eclipse中文语言包安装和设置中文Doc

    1.安装中文语言包 Eclipse所有的扩展功能都是以插件的形式添加上去的,安装插件时有多种形式,下面是比较常用的两种: 直接将插件中的文件复制到Eclipse对于的目录中.优点是安装时很方便,缺点是 ...

  6. Android之常见问题集锦Ⅰ

     Android中如何在ViewPager中使动态创建的ImageView铺满屏幕 最近在做东西的时候,有一个要求,就是把用于在ViewPager里面轮播的图片铺满屏幕,但是中间遇到的问题是,Imag ...

  7. 打造android偷懒神器———ListView的万能适配器

    如果你去做任何一个项目,我相信你都会跟我有一样的经历,最最普遍的就是列表显示ListView,当然,写N个自定义的适配器也是情理之中.虽说程序员本身就是搬砖,做这些枯燥无味的重复的事情也是理所当然,但 ...

  8. Mysql5.6 online ddl

    Innodb性能改善方面: --Users can add indexes and perform standard table alterations while the database rema ...

  9. 图解使用VS的安装项目打包程序

    背景 这段时间一直在做客户端程序的打包程序,遇到各种坑.因为以前没有任何这方面的经验,历经各种折腾,费尽九牛二虎之力总算是完成了. 虽然没有太多技术含量,但是因为挺繁琐的,所以还是在此记录一下. 由于 ...

  10. [Asp.net 5] ApplicationBuilder详解

    ApplicationBuilder(IApplicationBuilder接口),是OWIN的基础,而且里面都是代理.代理的代理,各种lambda表达式,估计要看这部分代码,很多人得头昏脑涨.今天就 ...