Oracle 优化统计数据之直方图(histograms)(二)

2014-11-24 17:27:03 · 作者: · 浏览: 3
------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------


1 - filter("SKEW"=1)



SQL> explain plan for select * from t1 where skew=10000;


Explained.


SQL> select * from table(dbms_xplan.display);


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3617692013


--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 909 | 6363 | 7 (15)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 909 | 6363 | 7 (15)| 00:00:01 |
--------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------


1 - filter("SKEW"=10000)

因为oracle假设列skew中的数据是均匀分布的所以基数评估cardinality=density*num_rows=0.09090901*10000=909.09,四舍五入就是909行.但是我们知道skew=1的记录只有1行而skew=10000的记录有9990行.这种假设必然导致错误的执行计划.例如,如果我们在列skew上创建一个B树索引,oracle将使用对谓词skew=10000行使用索引扫描并返回909行记录.
SQL> create index skew_idx on t1(skew);


Index created.


SQL> exec dbms_stats.gather_index_stats(user,'skew_idx');


PL/SQL procedure successfully completed.


SQL> explain plan for select * from t1 where skew=10000;


Explained.


SQL> select * from table(dbms_xplan.display);
Plan hash value: 3994350891
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 909 | 6363 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 909 | 6363 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | SKEW_IDX | 909 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------


2 - access("SKEW"=10000)

因为我们知道没有给出关于数据分布的额外信息,CBO假设列中的数据在最小值和最大值之间是均匀分布的所以选择了错误的执行计划.


oracle直方图
一旦对列创建直方图后,它将告诉CBO列中数据出现的频率.所以在上面的例子中如果对列skew创建直方图它将告诉优化顺skew=1的值只出现一次,skew=10000的值出现了9990次.因此它能让优化器选择最优的执行计划.

在oracle中有两种类型的直方图.第一种是oracle会选择存储列中每一个不同值以及其出现的频率,称这种为宽度平衡直方图或频率直方图.这对于列有少量的不同值来说是有效和可能的方式.然而当列有大量不同值时要存储每一个不同值以及其出现的频率是不可能的.当然在无限资源(存储空间和计算能力和解析时间)的情况下,可以在任何情况下对每一个不同值存储其出现的频率来对优化器提供最终的信息,但是在真实的环境中这是不可能的.所以oracle使用高度平衡直方图来存储这样的数据.oracle会根据列中不同值的数量来自动判断所要创建直方图的类型,不同类型的直方图所描述的信息是不同的.

频率直方图(frequence histograms)
频率直方图列中的不同值被划到相同数量的桶中.每一个桶中存储的都是相同的值,也就是说频率直方图的桶数等于列的不同值的个数.buckets=ndv


下面的图表代表了列skew的数据分布情况.从图表中可以看出以下信息:
在x轴有11个桶,每一个桶代表了一个不同的值
Y轴显示了每一个不同值出现的频率.skew的1到10的频率是1,值10000的频率是9990
通过查看这样的信息可以很容易的说出一个特定值出现的频率


下面来对列skew创建一个频率直方图并查看数据是怎样存储在数据字典视图中的.现在对参数method_opt使用’for column column_name size n’来创建指定桶数的