Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2885520
  • 博文数量: 599
  • 博客积分: 16398
  • 博客等级: 上将
  • 技术积分: 6875
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-30 12:04
个人简介

WINDOWS下的程序员出身,偶尔也写一些linux平台下小程序, 后转行数据库行业,专注于ORACLE和DB2的运维和优化。 同时也是ios移动开发者。欢迎志同道合的朋友一起研究技术。 数据库技术交流群:58308065,23618606

文章分类

全部博文(599)

文章存档

2014年(12)

2013年(56)

2012年(199)

2011年(105)

2010年(128)

2009年(99)

分类: Oracle

2011-12-14 10:18:55

一个列的NUM_DISTINCT的个数与执行计划是否走INDEX SKIP SCAN的关系非常密切。
如果一个列的NUM_DISTINCT个数太多,并且建立了以这个列为前缀的组合索引,
查询的时候并没有带这个前缀列,那么ORACLE很可能就不会选择INDEX SKIP SCAN。
 
看如下一个简单的例子:
 
SQL> CREATE TABLE TEST AS SELECT * FROM ALL_OBJECTS;
 
表已创建。
 
SQL> CREATE INDEX IDX_TEST_01 ON TEST(OBJECT_TYPE,OBJECT_NAME);
 
索引已创建。
 
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'TEST',cascade=>TRUE);
 
PL/SQL 过程已成功完成。
 
首先创建了一个表和一个索引,并且收集了统计信息。

SQL> SELECT COLUMN_NAME,NUM_DISTINCT
  2  FROM USER_TAB_COL_STATISTICS
  3  WHERE TABLE_NAME='TEST' AND COLUMN_NAME='OBJECT_TYPE';
 
COLUMN_NAME          NUM_DISTINCT
-------------------- ------------
OBJECT_TYPE                    19
 
SQL> SET AUTOT TRACEONLY EXP
SQL> SET LINESIZE 300
SQL> SELECT * FROM TEST WHERE OBJECT_NAME='T';
 
Execution Plan
----------------------------------------------------------
Plan hash value: 3506850203
-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |     2 |   188 |    22   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST        |     2 |   188 |    22   (0)| 00:00:01 |
|*  2 |   INDEX SKIP SCAN           | IDX_TEST_01 |     2 |       |    20   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("OBJECT_NAME"='T')
       filter("OBJECT_NAME"='T')
 
由于OBJECT_TYPE的NUM_DISTINCT的个数不多,此时ORACLE可以选择INDEX SKIP SCAN。
 
SQL> EXEC DBMS_STATS.DELETE_COLUMN_STATS(USER,'TEST','OBJECT_TYPE');
 
PL/SQL 过程已成功完成。
 
SQL> SET AUTOT OFF
SQL> SELECT COLUMN_NAME,NUM_DISTINCT
  2  FROM USER_TAB_COL_STATISTICS
  3  WHERE TABLE_NAME='TEST' AND COLUMN_NAME='OBJECT_TYPE';
 
未选定行

SQL> SET AUTOT TRACEONLY EXP
SQL> SET LINESIZE 300
SQL> SELECT * FROM TEST WHERE OBJECT_NAME='T';
 
Execution Plan
----------------------------------------------------------
Plan hash value: 217508114
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     2 |   188 |   148   (2)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| TEST |     2 |   188 |   148   (2)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("OBJECT_NAME"='T')
  
由于OBJECT_TYPE的列的统计信息被删掉,ORACLE无法判断OBJECT_TYPE的NUM_DISTINCT的格式,
此时ORACLE不会用到INDEX SKIP SCAN。
 

SQL> EXEC DBMS_STATS.SET_COLUMN_STATS(USER,'TEST','OBJECT_TYPE',DISTCNT=>19);
 
PL/SQL 过程已成功完成。
 
SQL> SELECT COLUMN_NAME,NUM_DISTINCT
  2  FROM USER_TAB_COL_STATISTICS
  3  WHERE TABLE_NAME='TEST' AND COLUMN_NAME='OBJECT_TYPE';
 
COLUMN_NAME          NUM_DISTINCT
-------------------- ------------
OBJECT_TYPE                    19
 
SQL> SET AUTOT TRACEONLY EXP
SQL> SET LINESIZE 300
SQL> SELECT * FROM TEST WHERE OBJECT_NAME='T';
 
Execution Plan
----------------------------------------------------------
Plan hash value: 3506850203
-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |     2 |   188 |    22   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST        |     2 |   188 |    22   (0)| 00:00:01 |
|*  2 |   INDEX SKIP SCAN           | IDX_TEST_01 |     2 |       |    20   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("OBJECT_NAME"='T')
       filter("OBJECT_NAME"='T')
      
      
通过手工修改列的NUM_DISTINCT的值,使得ORACLE可以再次利用到INDEX SKIP SCAN的执行计划。
阅读(2548) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~