什么是集群因子(Clustering Factor)呢?集群因子是通过一个索引扫描一张表时需要访问的表的数据块的数量。

集群因子的计算方法如下:

(1) 扫描一个索引;

(2) 比较某行的ROWID和前一行的ROWID,如果这两个ROWID不属于同一个数据块,那么集群因子增加1;

(3) 整个索引扫描完毕后,就得到了该索引的集群因子。

以上面集群因子的计算方式可以看出,集群因子反映了索引范围扫描可能带来的对整个表访问过程的IO开销情况,如果集群因子接近于表存储的块数,说明这张表是按照索引字段的顺序存储的。如果集群因子接近于行的数量,那说明这张表不是按索引字段顺序存储的。在计算索引访问成本时,集群因子十分有用。集群因子乘以选择性参数就是访问索引的开销。(是优化器决定是否用索引的关键因素)

官方说明:

----row存储的越有序,clustering factor的值越低

----当clustering factor很高时,说明index entry (rowid) 是    随机指向一些block的,在一个大的index range scan时,这样为了读取这些rowid指向的block,就需要一次又一次重复的去读这些block。

----当clustering factor值低时,说明index keys (rowid) 是指向的记录是存储在相同的block里,这样去读row时,只需要在同一个block里读取就可以了,这样减少重复读取blocks的次数

Index Clustering Factor说明

简单的说,Index Clustering Factor是通过一个索引扫描一张表,需要访问的表的数据块的数量,即对I/O的影响,也代表索引键存储位置是否有序。

(1)、如果越有序,即相邻的键值存储在相同的block,那么这时候Clustering Factor的值就越低;

(2)、如果不是很有序,即键值是随机的存储在block上,这样在读取键值时,可能就需要一次又一次的去访问相同的block,从而增加了I/O。

Clustering Factor的计算方式如下:

(1)、扫描一个索引(large index range scan);

(2)、比较某行的rowid和前一行的rowid,如果这两个rowid不属于同一个数据块,那么cluster factor增加1;

(3)、整个索引扫描完毕后,就得到了该索引的clustering factor。

如果clustering factor接近于表存储的块数,说明这张表是按照索引字段的顺序存储的。

如果clustering factor接近于行的数量,那说明这张表不是按索引字段顺序存储的。

在计算索引访问成本的时候,这个值十分有用。Clustering Factor乘以选择性参数(selectivity)就是访问索引的开销。

如果这个统计数据不能真实反映出索引的真实情况,那么可能会造成优化器错误的选择执行计划。另外如果某张表上的大多数访问是按照某个索引做索引扫描,那么将该表的数据按照索引字段的顺序重新组织,可以提高该表的访问性能。

测试

    产生问题

----查看一下数据库的版本----
SQL> select * from v$version where rownum=1;BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production----创建一张测试表jack----
SQL> create table jack as select * from dba_objects where 1=2;Table created.----将数据无序的插入jack表中----
SQL> begin2      for i in 1..10 loop3        insert /*+ append */ into jack select * from dba_objects order by i;4      commit;5    end loop;6  end;7  /PL/SQL procedure successfully completed.SQL> select count(*) from jack;COUNT(*)
----------725460----查看一下表的大小-----
SQL> set wrap off
SQL> col owner for a10;
SQL> col segment_name for a15;
SQL> select segment_name,blocks,extents,bytes/1024/1024||'M' "size" from user_segments where segment_name='JACK';SEGMENT_NAME     BLOCKS    EXTENTS   size
------------- ---------- ---------- --------
JACK             11264       82      88M----在object_id上创建索引----
SQL> create index jack_ind on jack(object_id);Index created.----查看一下索引的大小----
SQL> select segment_name,segment_type,blocks,extents,bytes/1024/1024||'M' "size" from user_segments where segment_name='JACK_IND';SEGMENT_NAME    SEGMENT_TYPE      BLOCKS     EXTENTS     size
------------ ------------------ ---------- ---------- ---------
JACK_IND           INDEX           1664         28        13M----在没有收集相关的统计信息之前,查看一下index clustering factor----
SQL> select index_name,clustering_factor,num_rows from user_indexes where index_name='JACK_IND';INDEX_NAME      CLUSTERING_FACTOR   NUM_ROWS
--------------- ----------------- ----------
JACK_IND              725460         725460----简单的收集一下统计信息----
SQL> exec dbms_stats.gather_table_stats(user,'jack',cascade=>true);PL/SQL procedure successfully completed.----再次查看index clustering factor----
SQL> select index_name,clustering_factor,num_rows from user_indexes where index_name='JACK_IND';INDEX_NAME     CLUSTERING_FACTOR   NUM_ROWS
-------------- ----------------- ----------
JACK_IND              725460       725460       ----显然统计信息收集前和后,clustering factor值不变,说在创建索引的时候,会收集表中的数据真正的行数。并且这里的clustering factor等num_rows,也说明表的clustering factor是无序的。----查看一个确定值,然后查看执行计划----
SQL> explain plan for select * from jack where object_id=1501;Explained.SQL> select * from table(dbms_xplan.display);PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2860868395--------------------------------------------------------------------------------
| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Ti
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |           |    10 |   970 |    13     (0)| 00
|   1 |  TABLE ACCESS BY INDEX ROWID| JACK     |    10 |   970 |    13     (0)| 00
|*  2 |   INDEX RANGE SCAN        | JACK_IND |    10 |       |     3     (0)| 00
--------------------------------------------------------------------------------Predicate Information (identified by operation id):PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------2 - access("OBJECT_ID"=1501)14 rows selected.                 ----在这里走了索引,cost为13.SQL> alter system flush buffer_cache;System altered.SQL> set autotrace traceonly;----查询一个范围的执行计划----
SQL> select * from jack where object_id>1000 and object_id<2000;9880 rows selected.Execution Plan
----------------------------------------------------------
Plan hash value: 949574992--------------------------------------------------------------------------
| Id  | Operation      | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |     |  9657 |   914K|  1824   (1)| 00:00:22 |
|*  1 |  TABLE ACCESS FULL| JACK |  9657 |   914K|  1824   (1)| 00:00:22 |
--------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------1 - filter("OBJECT_ID"<2000 AND "OBJECT_ID">1000)Statistics
----------------------------------------------------------0   recursive calls0   db block gets10993 consistent gets10340 physical reads0   redo size471945 bytes sent via SQL*Net to client7657  bytes received via SQL*Net from client660   SQL*Net roundtrips to/from client0   sorts (memory)0   sorts (disk)9880  rows processed       ----注意,object_id上是有索引的,但是这里并没有使用索引,而是使用了全表扫描。SQL> alter system flush buffer_cache;System altered.----强制走索引,查看执行计划----
SQL> select /*+ index(jack jack_ind) */ * from jack where object_id>1000 and object_id<2000;9880 rows selected.Execution Plan
----------------------------------------------------------
Plan hash value: 2860868395----------------------------------------------------------------------------------------
| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |           |  9657 |   914K|  9683     (1)| 00:01:57 |
|   1 |  TABLE ACCESS BY INDEX ROWID| JACK     |  9657 |   914K|  9683     (1)| 00:01:57 |
|*  2 |   INDEX RANGE SCAN        | JACK_IND |  9657 |       |    24     (0)| 00:00:01 |
----------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("OBJECT_ID">1000 AND "OBJECT_ID"<2000)Statistics
----------------------------------------------------------0    recursive calls0    db block gets10561  consistent gets164    physical reads0    redo size988947  bytes sent via SQL*Net to client7657   bytes received via SQL*Net from client660    SQL*Net roundtrips to/from client0    sorts (memory)0    sorts (disk)9880   rows processed
----强制走索引之后,使用了index range scan,但是cost变成了9683,而全表扫描时是1824.
----还有比较一下两次查询中物理读的情况:全表扫描的物理读明显比索引的要高很多,但是Oracle却没有使用索引。
----因此Oracle认为走索引的Cost比走全表扫描大,而是大N倍,CBO是基于Cost来决定执行计划的。
----由此得出,对于索引的Cost,Oracle是根据clustering factor参数来计算的,而该实验中的clustering factor参数是很高的,数据存储无序。这就造成了Oracle认为走索引的cost比全表扫描的大。

解决问题:

----通过上面的分析,可以看出,要降低clustering factor才能解决问题,而要解决clustering factor,就需要重新对表的存储位置进行排序。--------重建jakc表----
SQL> create table echo as select * from jack where 1=0;Table created.SQL> insert /*+ append */ into echo select * from jack order by object_id;725460 rows created.SQL> commit;Commit complete.SQL> truncate table jack;Table truncated.SQL> insert /*+ append */ into jack select * from echo;725460 rows created.SQL> commit;Commit complete.----查看表和索引的信息----
SQL> select segment_name,blocks,extents,bytes/1024/1024||'M' "size" from user_segments where segment_name='JACK';SEGMENT_NAME    BLOCKS    EXTENTS     size
------------- ---------- ---------- -----------
JACK             11264       82        88MSQL> select segment_name,segment_type,blocks,extents,bytes/1024/1024||'M' "size" from user_segments where segment_name='JACK_IND';SEGMENT_NAME    SEGMENT_TYPE      BLOCKS     EXTENTS    size
------------ ------------------ ---------- ---------- -------------
JACK_IND            INDEX          1536          27     12MSQL> select index_name,clustering_factor,num_rows from user_indexes where index_name='JACK_IND';INDEX_NAME     CLUSTERING_FACTOR NUM_ROWS
------------- ----------------- ----------
JACK_IND             725460      725460----对索引进行rebuild----
SQL> alter index jack_ind rebuild;Index altered.----查看cluster factor----
SQL> select index_name,clustering_factor,num_rows from user_indexes where index_name='JACK_IND';INDEX_NAME      CLUSTERING_FACTOR  NUM_ROWS
--------------- ----------------- ----------
JACK_IND               10327       725460    ------注意这里的Factor,已经变成10327,我们收集一下表的统计信息,然后与表的block进行一次比较。SQL> exec dbms_stats.gather_table_stats(user,'jack',cascade=>true);PL/SQL procedure successfully completed.SQL> select blocks from dba_tables where table_name='JACK';BLOCKS
----------10474   ----表jack实际使用的block是10474,clustering factor是10327基本还是比较接近了,这也说明相邻的row是存储在相同的block里。SQL> select index_name,clustering_factor,num_rows from user_indexes where index_name='JACK_IND';INDEX_NAME               CLUSTERING_FACTOR   NUM_ROWS
------------------------------ ----------------- ----------
JACK_IND                   10327     725460SQL> alter system flush buffer_cache;System altered.SQL> set autotrace traceonly;----再次查看之前sql的执行计划----
SQL> select * from jack where object_id>1000 and object_id<2000;9880 rows selected.Execution Plan
----------------------------------------------------------
Plan hash value: 2860868395----------------------------------------------------------------------------------------
| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |           |  9657 |   914K|   162     (0)| 00:00:02 |
|   1 |  TABLE ACCESS BY INDEX ROWID| JACK     |  9657 |   914K|   162     (0)| 00:00:02 |
|*  2 |   INDEX RANGE SCAN        | JACK_IND |  9657 |       |    24     (0)| 00:00:01 |
----------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("OBJECT_ID">1000 AND "OBJECT_ID"<2000)Statistics
----------------------------------------------------------1   recursive calls0   db block gets1457  consistent gets151   physical reads0   redo size988947  bytes sent via SQL*Net to client7657  bytes received via SQL*Net from client660   SQL*Net roundtrips to/from client0   sorts (memory)0   sorts (disk)9880  rows processed----注意这里的cost已经降到了162,性能提升还是非常明显。

小结

    通过以上说明和测试,可以看到clustering factor也是索引健康的一个重要判断的标准。其值越低越好。它会影响CBO选择正确的执行计划。但是注意一点,clustering factor总是趋势与不断恶化的。

转载于:https://blog.51cto.com/newcourage/1942656

Oracle:集群因子相关推荐

  1. linux+Oracle集群课程全面升级

    作为国内最早从事开源架构师级课程研发的公司,从2006年10月开始,荣新稳步提升,将互联网运维作为主导就业方向,并将Linux集群架构课程发展成为国内最顶级.覆盖技术最全面的Linux课程,作为荣新I ...

  2. was连接oracle rac集群,Oracle集群(RAC)及 jdbc 联接双机数据库

    oracle集群url配置 oracle集群中plsql和java程序连接方式非集群中plsql连接配置: www.2cto.com DB1_193 = (DESCRIPTION = (ADDRESS ...

  3. 【Oracle 集群】Linux下Oracle RAC集群搭建之基本测试与使用(九)

    Oracle 11G RAC数据库安装(九) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总 ...

  4. 2.oracle的安装常识,Oralce服务器,oracle集群,oracle服务介绍,用户解锁相关

     1 oracle的安装常识(oracle10g和oracle11g的版本差别): A 安装目录都不要有中文和空格 B oracle10g支持winxp 不支持win7,8和vista;Oracl ...

  5. linux下安装oracle集群,【Oracle 集群】Linux下Oracle RAC集群搭建之Oracle DataBase安装(八)...

    目录 数据库安装 继oracle集群安装之后,接下来也是最重要的数据库安装,整个数据库安装难度不大,用户以oracle用户身份登录RAC1主节点,对解压后的文件安装.主节点下安装后,其他所有结点自动安 ...

  6. mac node oracle,将Python3.5(Mac OS X El Capitan)连接到Oracle集群(远程)

    我正在尝试将Python3.5(Mac OS X El Capitan)连接到Oracle集群(远程). 对于安装cx_Oracle,我设置了: export ORACLE_HOME=/Applica ...

  7. 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之集群概念介绍(一)

    集群概念介绍(一)) 白宁超 2015年7月16日 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习 ...

  8. ORACLE集群日志收集,【RAC】Oracle RAC集群环境下日志文件结构

    在Oracle RAC环境中,对集群中的日志的定期检查是必不可少的.通过查看集群日志,可以早期定位集群环境中出现的问题,以便将问题消灭在萌芽状态.简单介绍一下有关Oracle集群环境中日志的结构,方便 ...

  9. oracle数据库集群采用的是形式,铁道部采用Oracle集群数据库进行TMIS系统“三级建库”...

    综述 铁道部利用Oracle9i集群数据库系统(Oracle9i RAC),顺利开展铁道部运输管理信息系统(TMIS)的"三级建库"工程--在各铁路局和铁路分局利用Oracle9i ...

最新文章

  1. 移动端web开发常见问题
  2. 基于pygame的贪吃蛇游戏
  3. centos6.5安装配置zabbix3.0.3
  4. 谷歌浏览器安卓版_谷歌Chrome Canary 82安卓版现可复制图片到剪贴板
  5. 前端面试题汇总(jQuery)
  6. flex皮肤制作---通过flash
  7. 学习Google Chrome源码
  8. “斗”转星移,高精度(NTP网络授时)北斗授时系统
  9. 声音信号处理基频检测和时频分析
  10. 如何测算信息化项目软件运维费?
  11. unity球体添加光源_Unity 3D光源-Point Light点光源详解/灯泡、模拟灯光效果教程
  12. 国产系统为什么用linux,为什么国产操作系统不用Unix,而是集体用Linux
  13. Unity WebGL 发布内存优化
  14. H3C交换机常用配置
  15. fluxion-wifi破解/钓鱼
  16. VRP和调度问题的主流精确算法和启发式算法
  17. 【动态规划】什么是动态规划
  18. web前端svg图标使用(关于阿里iconfont的symbol 引用)
  19. sketch的切图技巧总结:如何批量切出固定大小的切图并保留透明部分?
  20. 下载到的电子书格式是epub,这种格式如何打开?

热门文章

  1. php声明一个类的关键字,php中怎么实例化一个类
  2. .gitignore文件_Django项目.gitignore文件建议忽略文件清单及是否需要忽略数据库迁移文件...
  3. 2018-2019-2 20175224 实验五《网络编程与安全》实验报告
  4. 怎么查看一个网站是用什么语言编写的?
  5. EasyUI实现工地领款单项目
  6. CentOS中无法使用setup命令 -bash:setup: command not found
  7. extjs--combox用法
  8. 关于[一个基于WF的业务流程平台]表设计的说明
  9. 栈中函数调用原理_详解
  10. Android—Navigation的使用