ITPub博客

首页 > 数据库 > Oracle > oracle 聚簇因子及实验

oracle 聚簇因子及实验

原创 Oracle 作者:wanglinghua0907 时间:2024-01-22 09:51:56 0 删除 编辑

概念:

什么是聚簇因子

聚簇因子是基于表上索引列上的一个值,每一个索引都有一个聚簇因子。

用于描述索引块上与表块上存储数据在顺序上的相似程度,也就说表上的数据行的存储顺序与索引列上顺序是否一致。

在全索引扫描中,CF的值基本上等同于物理I/O或块访问数,如果相同的块被连续读,则Oracle认为只需要1次物理I/O。

好的CF值接近于表上的块数,而差的CF值则接近于表上的行数。

聚簇因子在索引创建时就会通过表上存存在的行以及索引块计算获得。


1.clustering factor(聚簇因子)越低越好,会影响CBO的选择。

2.hint完比对物理读,如果走全表且物理读过高,建议还是走索引,调低聚簇因子。

3.随着时间,clustering factor总是趋势与不断恶化的


测试:

创建问题(怎么都不走索引,hint)


创建测试表jack

create table jack as select * from dba_objects where 1=2;


将数据无序的插入jack表中

 begin
    for i in 1..10 loop
      insert /*+ append */ into jack select * from dba_objects order by i;
    commit;
  end loop;
end;
/



查询行数

select count(*) from jack;


查看一下表的大小

set wrap off
col owner for a10;
col segment_name for a15;
select segment_name,blocks,extents,bytes/1024/1024||'M' "size" from dba_segments where
segment_name='JACK';

SEGMENT _NAME JACK BLOCKS 13312 EXTENTS size 84 184M


在object_id上创建索引

create index jack_ind on jack(object_id);


查看一下索引的大小

select segment_name,segment_type,blocks,extents,bytes/1024/1024||'M' "size" from dba_segments where

segment_name='JACK_IND';

SEGMENT _NAME JACK-IND SEGMENT _TYPE INDEX BLOCKS 2048 EXTENTS size 31 16M


在没有收集相关的统计信息之前,查看一下index clustering factor

select index_name,clustering_factor,num_rows from dba_indexes where index_name='JACK_IND';

INDEX_NAME JACK_IND CLUSTERING_FACTOR 86274B NUM_ROWS 86274B


简单的收集一下统计信息

exec dbms_stats.gather_table_stats(user,'jack',cascade=>true);


再次查看index clustering factor

select index_name,clustering_factor,num_rows from dba_indexes where index_name='JACK_IND';

INDEX_NAME JACK_IND CLUSTERING_FACTOR 862740 NUM_ROWS 86274B


----显然统计信息收集前和后,clustering factor值不变,说在创建索引的时候,会收集表中的数据真正的行数。

并且这里的clustering factor等num_rows,也说明表的clustering factor是无序的。


查看一个确定值,然后查看执行计划

explain plan for select * from jack where object_id=1501;

select * from table(dbms_xplan.display);

Plan hash value: 2868868395 Operation SELECT STATEMENT TABLE ACCESS BY INDEX 21 INDEX RANGE SCAN ROWIDI Name JACK JACK_IND I Rows Bytes I 98B I 98B I cost ("CPU) I Ti 13 13 Predicate Information 14 rows selected. (identified by operation


--走了索引,cost13


清空buffer cache(当前为测试,生产千万别做)

alter system flush buffer_cache;


取一个查范围的执行计划

set autotrace traceonly;

select * from jack where object_id>1000 and object_id<2000;

Execution Plan Plan hash value : 949574992 Id Operation SELECT STATEMENT TABLE ACCESS FULLI Name JACK I Rows 9872 | 9872 | Bytes I 944K I 944K I Cost Time 3389 3389 Predicate Information (identified by operation 1 - eeee AND Statistics 12995 12328 518288 7839 667 ggge recursive calls db block gets consistent gets physical reads redo size bytes sent via SQL*Net to client bytes received via SQL*Net from client SQL*Net roundtrips to/from client sorts (memory) sorts (disk) rows processed


--不走索引,走的全表扫描


清空buffer cache(当前为测试,生产千万别做)

alter system flush buffer_cache;


强制走索引,查看执行计划

select /*+ index(jack jack_ind) */ * from jack where object_id>1000 and object_id<2000;

Execution Plan Plan hash value 21 : 286€868395 Ope ration SELECT STATEMENT Name JACK JACK_IND I Rows 9872 9872 9872 Bytes I 944K I 944K I cost Ti 9899 9899 24 TABLE ACCESS INDEX RANGE Predicate Information BY INDEX ROWIDI SCAN (identified by operation id): 2 - access( AND Statistics 18680 164 1837789 7839 667 9990 recursive calls db block gets consistent gets physical reads redo size bytes sent via SQL*Net to client bytes received via SQL*Net from client SQL *Net roundtrips to/from client sorts (memory) sorts (disk) rows processed


----强制走索引之后,使用了index range scan,但是cost变成了9683,而全表扫描时是1824.

----还有比较一下两次查询中物理读的情况:全表扫描的物理读明显比索引的要高很多,但是Oracle却没有使用索引。

----因此Oracle认为走索引的Cost比走全表扫描大,而是大N倍,CBO是基于Cost来决定执行计划的。

----由此得出,对于索引的Cost,Oracle是根据clustering factor参数来计算的,而该实验中的clustering factor参数

是很高的,数据存储无序。这就造成了Oracle认为走索引的cost比全表扫描的大。


解决问题:

两种思路(1.聚簇因子方面  2.块方面):

1.方法一(推荐)

调整聚簇因子

exec dbms_stats.set_index_stats(ownname => 'DEF',indname => 'JACK_IND',clstfct => 600000);


select index_name,clustering_factor,num_rows from dba_indexes where index_name='JACK_IND';

SQL> select index_name, clustering_factor , num_rows from dba_indexes w INDEX_NAME JACK_IND CLUSTERING_FACTOR NUM_ROWS ceeeea 86274B


聚簇因子接近块数好,约小会比较好。无绝对。


查看表存储块数

select sum(blocks) from dba_tables where table_name='JACK' and owner='DEF';


查看表行数

select count(*) from def.jack;


2.方法二(调整聚簇因子)(收益很小)

对索引进行rebuild

alter index jack_ind rebuild;


不一定能解决问题,因为索引通常是有序的,一般无序的是表上的数据


3.方法三(调整表的块)(推荐)

定期重构堆表,使表与索引上的数据顺序更加接近

create table tmp_article_info as select * from article_info;

or

在线重定义


4.方法四

使用聚簇表


Tips:

1.表dml操作后,收集统计信息才能查看最新的聚簇因子。

2.alter table move tabname并不会影响CF的值,该功能只是移动高水位线,且不释放空间。

3.重建索引对CF的值收效甚微,因为原始表数据存储顺序未发生根本变化。

4.CF的值是影响查询分析器对执行计划的评估与生成的因素之一(即是否走索引还是全表扫描,嵌套连接

时哪个表为驱动表等)


参考:
部分内容参考Leshami



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69980685/viewspace-3004609/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
Oracle ACE、sql server、oceanbase数据库专家,拥有7年以上的大型数据库运维经验,主方向oracle,擅长故障排除、诊断,大体量(TB)迁移,异常故障修复等。拥有丰富主导大型项目经验。服务行业包括:运营商、银行、金融业、政府单位、医疗、制造业、高校等等。

注册时间:2020-07-31

  • 博文量
    116
  • 访问量
    88779