日期:2014-05-16  浏览次数:20745 次

(1)oracle单表选择率(selectivity)

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 C10D
SQL> 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   |