oracle簇字段,oracle 聚簇因数(Cluster Factor)

本文通过一个实际的Oracle数据库性能优化案例,展示了聚簇因子(Cluster Factor)如何影响索引的使用。当查询所需返回的行数远小于表总行数,但执行计划仍显示全表扫描时,发现聚簇因子过高是关键原因。通过调整聚簇因子并重新组织数据,使得查询能够有效利用索引,从而显著提升了查询效率。此外,还探讨了直方图在决策索引使用中的作用,验证了聚簇因子对性能优化的重要性。
摘要由CSDN通过智能技术生成

oracle 聚簇因子(Cluster Factor)

文章来源:http://www.itpub.net/thread-1317424-1-1.html#

一次简单的性能优化诊断,聚簇因子过高导致全表扫描。

业务人员反映一个查询非常慢:

--------------------------------------------

select * from ab44 where aae002=201006;

--------------------------------------------

查看执行计划,是全表扫描

SQL> explain plan for select * from ab44 where aae002=201006;

已解释。

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------

Plan hash value: 781340439

--------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------

| 0 | SELECT STATEMENT | | 10554 | 865K| 8777 (3)| 00:01:46 |

|* 1 | TABLE ACCESS FULL| AB44 | 10554 | 865K| 8777 (3)| 00:01:46 |

--------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

PLAN_TABLE_OUTPUT

--------------------------------------------

1 - filter("AAE002"=201006)

已选择13行。

看看查询应该返回多少数据量,还有这个表有多少记录。

SQL> select count(*) from ab44 where aae002='201006';

COUNT(*)

----------

576

SQL> select count(*) from ab44;

COUNT(*)

----------

3310023

SQL> select 576/3310023 from dual;

576/3310023

-----------

.000174017

查询所需返回的行数仅占表的很小比例,如果有索引的话,应该索引扫描才对。

查看表的索引,发现在aae002字段上有一个复合索引,四个字段组成AAE002, AAE003, AAB001, AAE140。既然有索引,为什么没有使用呢?莫非是缺失统计信息。

查看表、索引、直方图的信息都有。而且统计信息相对还是比较新的。

SQL> select num_rows,blocks,avg_row_len from user_tables where table_name='AB44';

NUM_ROWS BLOCKS AVG_ROW_LEN

---------- ---------- -----------

3310017 44538 84

SQL> select distinct_keys,clustering_factor,num_rows from USER_IND_STATISTICS WHERE table_name='AB44' and index_name='PK_AB44';

DISTINCT_KEYS CLUSTERING_FACTOR NUM_ROWS

------------- ----------------- ----------

3309447 3299907 3309447

SQL> SELECT * FROM USER_HISTOGRAMS WHERE table_name='AB44';

略。。。。。。。。。。。。。。。。。。。。。。。。

查询到索引的统计信息的时候,发现索引的聚簇因子非常高,非常接近表的行数。重新分析表,依然如此。

修改聚簇因子后,查看执行计划,已经是索引扫描了。

begin

dbms_stats.set_index_stats(ownname => 'NCSI',indname => 'PK_AB44',clstfct => '7800');

end;

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

-----------------------------------------------------------

-------------

Plan hash value: 1618544176

---------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------

| 0 | SELECT STATEMENT | | 10554 | 865K| 239 (1)| 00:00:03 |

| 1 | TABLE ACCESS BY INDEX ROWID| AB44 | 10554 | 865K| 239 (1)| 00:00:03 |

|* 2 | INDEX RANGE SCAN | PK_AB44 | 10554 | | 45 (0)| 00:00:01 |

---------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("AAE002"=201006)

已选择14行。

但是到这里并不能说一定是聚簇因子导致的,因为很可能是还有直方图的因素。查询列AAE002上的唯一值个数为420,而表的记录总数是330万,如果没有直方图的话,ORACLE评估返回的行数应该是3300000/420=7857条记录,按照这个记录量来看,返回的行数占表记录总数的0.2%.根据经验,应该也能使用到索引才对。

于是重新收集统计信息,取消直方图。查看执行计划,还是全表扫描。看来直方图在本例中所占影响因素较小,还是聚簇因子过大惹的祸。

暂时通过修改聚簇因子暂时改善了性能问题,晚上的时候,按照索引字段的顺序重新创建了表。

SQL>create table AB44_TEMP as select * from ab44 where 1=0;

SQL>INSERT /*+ append */INTO AB44_TEMP SELECT * FROM AB44 ORDER BY AAE002, AAE003, AAB001, AAE140;

SQL>commit;

SQL>drop table ab44;

SQL>alter table ab44_temp rename to ab44;

重新创建索引,分析表。重建后的聚簇因子只有60197,远远小于之前的 3299907。查看执行计划,也对了。

SQL> explain plan for select * from ab44 where aae002=201006;

已解释。

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

----------------------------------------------------------------

-------------

Plan hash value: 2627288474

---------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------

| 0 | SELECT STATEMENT | | 10799 | 885K| 249 (1)| 00:00:03 |

| 1 | TABLE ACCESS BY INDEX ROWID| AB44 | 10799 | 885K| 249 (1)| 00:00:03 |

|* 2 | INDEX RANGE SCAN | AB44_TEMP_IND | 10799 | | 50 (0)| 00:00:01 |

---------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("AAE002"=201006)

已选择14行。

而且为了验证本例确实是由于聚簇因子过大占了决定因素。我把重建后的表直方图取消掉,重新查询,每一个AAE002的值都是索引扫描了。而之前聚簇因子较大的无直方图的实验,还是全表扫描。进一步证明了本例聚簇因子的影响占了很大比例。

BEGIN

DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'NCSI',

TABNAME => 'AB44',

CASCADE => TRUE,

METHOD_OPT => 'for ALL columns SIZE 1');

END;

SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=201002;

SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=201006;

SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=198701;

SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=199101;

SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=199804;

SQL> select object_name,operation,options from plan_table where id=2;

OBJECT_NAME OPERATION OPTIONS

-------------------- ------------------------------ --------------------

AB44_TEMP_IND INDEX RANGE SCAN

AB44_TEMP_IND INDEX RANGE SCAN

AB44_TEMP_IND INDEX RANGE SCAN

AB44_TEMP_IND INDEX RANGE SCAN

AB44_TEMP_IND INDEX RANGE SCAN

查看表有多大

select sum(bytes)/1024/1024 from user_segments where segment_name='X1';

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值