在11g中,Oracle在统计信息方面进行了进一步的增强。
这篇介绍多列统计信息。
11.2中Oracle增加了多列统计的功能。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database11gEnterprise Edition Release11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
SQL> create table t_multi_col
2 as select *
3 from dba_extents
4 where file_id < 4;
表已创建。
SQL> select count(*) from t_multi_col;
COUNT(*)
----------
12038
SQL> select count(distinct file_id) file_id, count(distinct relative_fno) r_file_id
2 from t_multi_col;
FILE_ID R_FILE_ID
---------- ----------
3 3
SQL> create index ind_multi_col_file
2 on t_multi_col(file_id, relative_fno);
索引已创建。
SQL> exec dbms_stats.gather_table_stats(user, 't_multi_col')
PL/SQL过程已成功完成。
SQL> explain plan for
2 select *
3 from t_multi_col
4 where file_id = 2;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------
Plan hash value: 1795650781
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8391 | 565K| 27 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T_MULTI_COL | 8391 | 565K| 27 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("FILE_ID"=2)
已选择13行。
SQL> explain plan for
2 select *
3 from t_multi_col
4 where file_id = 2
5 and relative_fno = 2;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 1189586738
--------------------------------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | |2797| 188K| 19 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_MULTI_COL |2797| 188K| 19 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_MULTI_COL_FILE |2797| | 4 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("FILE_ID"=2 AND "RELATIVE_FNO"=2)
已选择14行。
SQL> select distinct file_id, relative_fno
2 from t_multi_col;
FILE_ID RELATIVE_FNO
---------- ------------
1 1
2 2
3 3
Oracle判断是否使用索引,是根据选择度来判断,对于上面的SQL,由于列FILE_ID的选择度是1/3,因此查询的时候Oracle认为使用索引的代价大于全表扫描。
如果指定了两个列的情况,那么Oracle认为同时指定两个列的选择度等于每个单列选择度相乘,对于上面的例子就是1/3×1/3=1/9。
如果查询的选择度是1/9,那么Oracle认为索引的效率比全表扫描更高一些。
但是对于当前的例子,FILE_ID和RELATIVE_FNO是强关联性,如果FILE_ID确定,那么RELATIVE_FNO也基本确定,从上面最后的查询也可以看到,事实上同时指定了FILE_ID和RELATIVE_FNO,查询的选择度仍然是1/3。
而对于这种强相关性,跟业务逻辑密切相关,因此Oracle没有办法自动处理。
在11.2中,Oracle增加了COLUMN GROUP的概念,将这种强关联的列组合在一起进行统计信息的收集:
SQL> exec dbms_stats.gather_table_stats(user, 't_multi_col', method_opt => 'for columns (file_id, relative_fno) size skewonly')
PL/SQL过程已成功完成。
SQL> explain plan for
2 select *
3 from t_multi_col
4 where file_id = 2
5 and relative_fno = 2;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 1795650781
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8391 | 598K| 27 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T_MULTI_COL | 8391 | 598K| 27 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RELATIVE_FNO"=2 AND "FILE_ID"=2)
已选择13行。
这是一个最简单的例子,直接在收集统计信息的时候指定了对列组收集信息。因此Oracle对于这个查询选择了全表扫描,而没有去选择索引扫描。
oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html