日期:2014-05-16 浏览次数:20468 次
一次简单的性能优化诊断,聚簇因子过高导致全表扫描。 业务人员反映一个查询非常慢: -------------------------------------------- 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%.根据经验,应该也能使用到索引才对。 于是重新收集统计信息,取消直方图。查看执行计划,还是全表扫描。看来直方图在本例中所占影响因素较小,还是聚簇因子过大惹的