直方图
当某列数据分布不均衡,为了让CBO能生成最佳的执行计划,我们可能需要对表收集直方图,直方图最大的桶数(Bucket)是254。
收集直方图是一个很耗时的过程,如无必要,千万别去收集直方图。
Oracle的直方图有两种:
一种是频率直方图(FREQUENCY HISTOGRAM),当列中Distinct_keys 较少(小于254),如果不手工指定直方图桶数(BUCKET),Oracle就会自动的创建频率直方图,并且桶数(BUCKET)等于Distinct_Keys。
一种是高度平衡直方图(HEIGHT BALANCED),当列中Distinct_keys大于254,如果不手工指定直方图桶数(BUCKET),Oracle就会自动的创建高度平衡直方图。
直方图用在什么情况下?
列的值分布非常不均衡的时候,并且where条件中经常用到这个列。
直方图都准吗?
不一定。如果一个字段distinct值的个数非常多,基本接近主键的distinct值的个数,就没必要做直方图,直方图也不一定100%准确。
相关的@脚本在文章的最后面提供。
SQL> drop table a;
表已删除。
SQL> create table a as select * from dba_objects where rownum<=10000;
表已创建。
SQL> @anatab --常规的表分析
输入 ownname 的值: ggs
输入 tabname 的值: a
输入 estimate_percent 的值: 100
输入 skewonly_repeat_auto 的值: auto
输入 degree 的值: 4
PL/SQL 过程已成功完成。
已用时间: 00: 00: 00.26
SQL> @getcolstat --字段的直方图
输入 owner 的值: ggs
输入 table_name 的值: a
COLUMN_NAME NUM_ROWS CARDINALITY SELECTIVITY HISTOGRAM NUM_BUCKETS LAST_ANALYZED
---------------- ---------- ----------- ----------- --------------------- --------------
SECONDARY 10000 1 .01 NONE 1 28-7月 -14
GENERATED 10000 2 .02 NONE 1 28-7月 -14
TEMPORARY 10000 2 .02 NONE 1 28-7月 -14
STATUS 10000 1 .01 NONE 1 28-7月 -14
TIMESTAMP 10000 350 3.5 NONE 1 28-7月 -14
LAST_DDL_TIME 10000 385 3.85 NONE 1 28-7月 -14
CREATED 10000 303 3.03 NONE 1 28-7月 -14
OBJECT_TYPE 10000 34 .34 NONE 1 28-7月 -14
DATA_OBJECT_ID 10000 1836 18.36 NONE 1 28-7月 -14
OBJECT_ID 10000 10000 100 NONE 1 28-7月 -14
SUBOBJECT_NAME 10000 27 .27 NONE 1 28-7月 -14
OBJECT_NAME 10000 7725 77.25 NONE 1 28-7月 -14
OWNER 10000 9 .09 NONE 1 28-7月 -14
已选择13行。
SQL>
SQL> select object_type,count(*) from a group by object_type;
OBJECT_TYPE COUNT(*)
------------------- ----------
INDEX 946
JOB CLASS 2
CONTEXT 2
TYPE BODY 82
PROCEDURE 50
RESOURCE PLAN 3
RULE 1
SCHEDULE 1
TABLE PARTITION 52
WINDOW 2
WINDOW GROUP 1
TABLE 841
TYPE 1088
VIEW 2953
LIBRARY 113
FUNCTION 68
TRIGGER 5
PROGRAM 3
CLUSTER 10
SYNONYM 2458
PACKAGE BODY 470
QUEUE 21
CONSUMER GROUP 5
eva lUATION CONTEXT 8
RULE SET 11
DIRECTORY 2
UNDEFINED 6
OPERATOR 15
SEQUENCE 102
LOB 128
PACKAGE 485
JOB 6
INDEX PARTITION 59
LOB PARTITION 1
已选择34行。
SQL> explain plan for select count(*) from a where object_type='INDEX';
已解释。
SQL> @getplan
'general,outline,starts'
Enter value for plan type:general
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2223038180
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 25 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
|* 2 | TABLE ACCESS FULL| A | 294 | 2058 | 25 (0)| 00:00:01 | --跟实际不一致,上面查出来的是946
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='INDEX')
SQL> select 10000/34 from dual; --说明rows中的294是 估算值=总行数/字段distinct值的个数
10000/34
----------
294.117647
已选择 1 行。
SQL>
SQL> @anatab_col
输入 owner 的值: ggs