Oracle索引梳理系列(九)- 浅谈聚簇因子对索引使用的影响及优化方法
版权声明:本文发布于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、聚簇因子的计算方法
聚簇因子大致的计算方法顺序如下:
- 进行一次索引全扫描
- 检查索引块中的rowid信息。比较前一个rowid与一个rowid是否指向同一个数据块。若不同,则聚簇因子加1.
- 当完成整个的索引扫面后,即得到该索引的聚簇因子的数值。
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索引梳理系列(九)- 浅谈聚簇因子对索引使用的影响及优化方法的更多相关文章
- [独孤九剑]Oracle知识点梳理(九)数据库常用对象之package
本系列链接导航: [独孤九剑]Oracle知识点梳理(一)表空间.用户 [独孤九剑]Oracle知识点梳理(二)数据库的连接 [独孤九剑]Oracle知识点梳理(三)导入.导出 [独孤九剑]Oracl ...
- 【公众号系列】浅谈SAP项目管理的技能
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[[公众号系列]浅谈SAP项目管理的技能 写 ...
- 【ASP.NET MVC系列】浅谈数据注解和验证
[ASP.NET MVC系列]浅谈数据注解和验证 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google C ...
- 【Fiori系列】浅谈SAP Fiori的设计美感与发展历程
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[Fiori系列]浅谈SAP Fiori的设计美 ...
- Spring5.0源码学习系列之浅谈BeanFactory创建
Spring5.0源码学习系列之浅谈BeanFactory创建过程 系列文章目录 提示:Spring源码学习专栏链接 @ 目录 系列文章目录 博客前言介绍 一.获取BeanFactory主流程 二.r ...
- 浅谈分词算法(5)基于字的分词方法(bi-LSTM)
目录 前言 目录 循环神经网络 基于LSTM的分词 Embedding 数据预处理 模型 如何添加用户词典 前言 很早便规划的浅谈分词算法,总共分为了五个部分,想聊聊自己在各种场景中使用到的分词方法做 ...
- 浅谈分词算法(4)基于字的分词方法(CRF)
目录 前言 目录 条件随机场(conditional random field CRF) 核心点 线性链条件随机场 简化形式 CRF分词 CRF VS HMM 代码实现 训练代码 实验结果 参考文献 ...
- 浅谈分词算法(3)基于字的分词方法(HMM)
目录 前言 目录 隐马尔可夫模型(Hidden Markov Model,HMM) HMM分词 两个假设 Viterbi算法 代码实现 实现效果 完整代码 参考文献 前言 在浅谈分词算法(1)分词中的 ...
- Oracle索引梳理系列(五)- Oracle索引种类之表簇索引(cluster index)
版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...
随机推荐
- 背后的故事之 - 快乐的Lambda表达式(二)
快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...
- ubuntu 启动MySql和安装python的MySQLdb模块
ubuntu一般会自己预安装mysql,你只需 /etc/init.d/mysql start|stop|restart|reload|force-reload|status 命令便可以实现mysq ...
- Eclipse中文语言包安装和设置中文Doc
1.安装中文语言包 Eclipse所有的扩展功能都是以插件的形式添加上去的,安装插件时有多种形式,下面是比较常用的两种: 直接将插件中的文件复制到Eclipse对于的目录中.优点是安装时很方便,缺点是 ...
- 爬虫技术 -- 进阶学习(十)网易新闻页面信息抓取(htmlagilitypack搭配scrapysharp)
最近在弄网页爬虫这方面的,上网看到关于htmlagilitypack搭配scrapysharp的文章,于是决定试一试~ 于是到https://www.nuget.org/packages/Scrapy ...
- 【分布式】Zookeeper数据与存储
一.前言 前面分析了Zookeeper对请求的处理,本篇博文接着分析Zookeeper中如何对底层数据进行存储,数据存储被分为内存数据存储于磁盘数据存储. 二.数据与存储 2.1 内存数据 Zooke ...
- LinqToDB 源码分析——DataContext类
LinqToDB框架是一个轻量级的ORM框架.当然,功能上来讲一定比不上Entity Framework的强大.但是在使用上总让笔者感觉有一点Entity Framework的影子.笔者想过可能的原因 ...
- 利用WCF的双工通讯实现一个简单的心跳监控系统
何为心跳监控系统? 故名思义,就是监控某个或某些个程序的运行状态,就好比医院里面的心跳监视仪一样,能够随时显示病人的心跳情况. 心跳监控的目的是什么? 与医院里面的心跳监视仪目的类似,监控程序运行状态 ...
- line-height不同单位之间的区别
line-height用来设置元素的行高. 该属性会影响行框的布局.在应用到一个块级元素时,它定义了该元素中基线之间的最小距离而不是最大距离. line-height 与 font-size 的计算值 ...
- DSP的Gel作用
转自:http://blog.csdn.net/azhgul/article/details/6660960 最近刚在研究Davinci系,特此MARK下,以资后续学习之用. DSP的Gel作用 1 ...
- Nginx配置文件nginx.conf中文详解(转)
######Nginx配置文件nginx.conf中文详解##### #定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_ ...