日期:2014-05-16 浏览次数:20819 次
CBO优化器是基于对当前经过特定测试的数据集中预期的行比率估计来计算基数的。此处的行数之比是一个数值,称为选择率(selectivity)。得到选择率之后,将其与输入行数进行简单相乘既可得到基数。
在理解选择性之前,必须得对user_tab_col_statistics视图有一定了解:
SQL> desc user_tab_col_statistics 名称 是否为空? 类型 ----------------------------------------- -------- ---------------------------- TABLE_NAME VARCHAR2(30) 表名 COLUMN_NAME VARCHAR2(30) 列名 NUM_DISTINCT NUMBER 列中distinct值的数目 LOW_VALUE RAW(32) 列的最小值 HIGH_VALUE RAW(32) 列的最大值 DENSITY NUMBER 当对列创建了直方图,则值不再等于1/NUM_DISTINCT。 NUM_NULLS NUMBER 列中的NULL值数目。 NUM_BUCKETS NUMBER Number of buckets in histogram for the column LAST_ANALYZED DATE 最近分析时间。 SAMPLE_SIZE NUMBER 分析样本大小。 GLOBAL_STATS VARCHAR2(3) 对分区采样,则-NO,否则-YES。 USER_STATS VARCHAR2(3) 统计信息由用户导入,则YES,否则-NO。 AVG_COL_LEN NUMBER 列的平均长度(以字节为单位) HISTOGRAM VARCHAR2(15) Indicates existence/type of histogram: NONE、FREQUENCY、HEIGHT BALANCED
下面创建一张测试表,并收集统计信息:
SQL> create table audience as
2 select
3 trunc(dbms_random.value(1,13)) month_no
4 from
5 all_objects
6 where
7 rownum <= 1200
8 ;
表已创建。
SQL> begin
2 dbms_stats.gather_table_stats(
3 user,
4 'audience',
5 cascade => true,
6 estimate_percent => null,
7 );ethod_opt => 'for all columns size 1'
method_opt => 'for all columns size 1'
8 );
9 end;
10 /
PL/SQL 过程已成功完成。
先查看一下上面表和列的统计信息:
SQL> select t.TABLE_NAME, t.NUM_ROWS, t.BLOCKS, t.SAMPLE_SIZE
2 from user_tables t;
TABLE_NAME NUM_ROWS BLOCKS SAMPLE_SIZE
---------- ---------- ---------- -----------
AUDIENCE 1200 5 1200
SQL> select s.table_name,
s.column_name,
s.num_distinct,
4 s.low_value,
s.high_value,
s.density,
7 s.num_nulls,
8 s.sample_size,
9 s.avg_col_len
10 from user_tab_col_statistics s;
TABLE_NAME COLUMN_NAM NUM_DISTINCT LOW_VALUE HIGH_VALUE DENSITY NUM_NULLS SAMPLE_SIZE AVG_COL_LEN
---------- ---------- ------------ ---------- ---------- ---------- ---------- ----------- -----------
AUDIENCE MONTH_NO 12 C102 C10D .083333333 0 1200 3
SQL> select rawtohex(1), rawtohex(12) from dual;
RAWT RAWT
---- ----
C102 C10DSQL> select count(a.month_no) from AUDIENCE a;
COUNT(A.MONTH_NO)
-----------------
1200 --可以看见,这里的值和NUM_ROWS是一样的。
SQL> select count(distinct a.month_no) from AUDIENCE a;
COUNT(DISTINCTA.MONTH_NO)
-------------------------
12 --可以看见,这里的值也和NUM_DISTINCT的值是一样的。SQL> select 1/12 from dual;
1/12
----------
.083333333 --这里的值和DENSITY一样的,计算公式为1/NUM_DISTINCT。
1、假如在上面创建了一张表,里面包含1200个人,如何才能确定其中有多少人的生日是在12月份。
SQL> select count(*) from AUDIENCE where month_no=12;
执行计划
----------------------
Plan hash value: 3337892515
-------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------
| 0 | SELECT STATEMENT |