?.何谓直方图:
直方图是?种统计?上的工具,并非Oracle专有。?常用于对?管理对象的某?面的质量情况进?管理,?常情况下它会表现为?种几何图形表,这?形表??实际???收集来的??理?象某?面的质量分布情况的数?绘制成的,?常会画成以数量为底边,以?度为高度的一系列连接起来的矩形图,因此直方图在统计?上也称为质量分布图?比如下图所示,??关?生化学?试成绩分数分布情况绘制的直方图?/p>
?Oracle?方图的作?
既然直方图是?种???理?象某?方面质量进?管理的描述工具,那么在Oracle?然它也是对Oracle???象质量的描述工具,这??象就是Oracle?重?的东西???数????/p>
在Oracle?方图?种?数据分布质量情况进?描述的工具?它会按照某?列不同?出现数量?少,以及出现的?率高低来绘制数据的分布情况,以便能?指?优化器根??分布做出正确的?择。在某些情况下,表的列中的数值分布将会影响优化器使用索引还是执?全表?的决策?当 where 子句的?具有不成比例数量的数?时,将出现这?情况,使得全表扫描比索引访问的成?低?这种情况下如果where 子句的过滤谓词列之上上有??理的正确的直方图,将会?优化器做出??选择发挥巨大的作?使得SQL?执?成本?低从而提升?能?/p>
?Oracle?用直方图的场合:
在分析表或索引时,直方图用于记录数据的分布??过获得该信?基于成本的优 化器就可以决定使用将返回少量行的索引,?避免使用基于限制条件返回?多?的索引?直方图的使用不受索引的限制,可以在表的任何列上构建直方图??/p>
构?直方图?主?的原因就?助优化器在表??重偏斜时做出更好的?划:例?,?果一到两??构成了表中的大部分数据(数据偏斜),相关的索引就可能无法帮助减少满足查询所?的I/O数量。创建直方图?让基于成?优化器知道何时使用索引才?合?,或何时应该根据WHERE子句?值返回表?0%的记录?/p>
通常情况下在以下场合??用直方图?/p>
?)?当Where子句引用了列值分布存在明显偏?列时:当这?偏差相当明显时,以至?WHERE 子句?值将会使优化器?择不同的执行?划?这时应该使用直方图来帮助优化器来修正执行路径?(注意:?果查?引用该列,则创建直方图没有意义?这种错?常?,??DBA 会在偏差列上创建柱状图,即使没有任何查?引用该列。)
?)?当列??致不正确的判?:这种情况?常会发生在多表连接时,例?,假设我???项的表联接,其结果集? 10 行?Oracle 将会以一种使??接的结果集(集合基数)尽?小的方式将表联接起来。?过在中间结果集?带更少的负载,查询将会运行得更快。为了使?结果?小化,优化器尝试?SQL 执?的分析阶段评估每?果集的集合基数?在偏差的列上拥有直方图将会极大地帮助优化器作出正确的决策??优化器??结果集的大小作出不??判断,它?会?择?种未达到?优化的表联接方法。因此向该列添加直方图经常会向优化器提供使用?佳联接方法所?的信???/p>
?直方图有两?类别,等频直方图与等高直方图?/p>
默?的,如果???斜列上的唯?值超过了254?那么ORACLE会?此列建立等高直方图,否则建立等?直方图??/p>
通过如下方式,建立表TAB,更新字段B,?列B产生倾斜。并在B列上创建索引?/p>
SQL> spool d:\hist.txt
SQL> create table tab (a number, b number);
表已创建?/p>
SQL>
SQL> begin
2 for i in 1..10000 loop
3 insert into tab values (i, i);
4 end loop;
5 commit;
6 end;
7 /
PL/SQL 过程已成功完成??/p>
SQL> update tab set b=5 where b between 6 and 9995;
已更?990行??/p>
SQL> commit;
提交完成?/p>
SQL> create index ix_tab_b on tab(b);
索引已创建??/p>
然后分析?强制使列B不产生直方图?/p>
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'SCOTT',
TABNAME => 'TAB',
CASCADE => TRUE,
METHOD_OPT => 'FOR COLUMNS B SIZE 1 ');
END;
查看视图USER_TAB_HISTOGRAMS,列B上只有最大?,?小?两条?录分??应?点号(endpoint_number??,这种显示?明列B没有直方图信???/p>
SQL>SELECT table_name,column_name,endpoint_number,endpoint_value FROM USER_TAB_HISTOGRAMS WHERE TABLE_NAME='TAB' ?/p>
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE
------------------------------ ---------------------------------------- --------------- --------------
TAB B 0 1
TAB B 1 10000
在没有直方图的情况下,在B列上进?等?查询的时?,都是索引范围??/p>
SQL> select * from tab where b=1;
执?计划
----------------------------------------------------------
Plan hash value: 439197569
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 6000 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TAB | 1000 | 6000 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IX_TAB_B | 1000 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
SQL> select * from tab where b=5;
已?择9991行??/p>
执?计划
----------------------------------------------------------
Plan hash value: 439197569
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 6000 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TAB | 1000 | 6000 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IX_TAB_B | 1000 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
收集直方图信??看看是?么效果?由于列B?值的?没有超过254因?产生的是等?直方图??/p>
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'SCOTT',
TABNAME => 'TAB',
CASCADE => TRUE,
METHOD_OPT => 'FOR ALL COLUMNS SIZE AUTO ');
END;
在B=1时?采用索引扫描,而B=5时?,已经采用全表?了,说明直方图起了作用??/p>
SQL> select * from tab where b=1;
执?计划
----------------------------------------------------------
Plan hash value: 439197569
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TAB | 1 | 6 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IX_TAB_B | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
SQL> select * from tab where b=5;
已?择9991行??/p>
执?计划
----------------------------------------------------------
Plan hash value: 1995730731
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9991 | 59946 | 6 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TAB | 9991 | 59946 | 6 (0)| 00:00:01 |
--------------------------------------------------------------------------
查看此时的直方图信息?/p>
SQL>SELECT TABLE_NAME, COLUMN_NAME, ENDPOINT_NUMBER, ENDPOINT_VALUE FROM USER_TAB_HISTOGRAMS
WHERE TABLE_NAME = 'TAB'?/p>
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE
------------------------------ ---------------------------------------- --------------- --------------
TAB B 1 1
TAB B 2 2
TAB B 3 3
TAB B 4 4
TAB B 9995 5
TAB B 9996 9996
TAB B 9997 9997
TAB B 9998 9998
TAB B 9999 9999
TAB B 10000 10000
其中EDNPOINT_NUMBER?计??EDNPOINT_VALUE?的??可以看出这种等频直方图统?的列的信?非常精确的?它为每??值分配了??。从执?计划的ROWS部分也可以看出ORACLE计算出来的cardinality?991,和实际的情况完全吻合??/p>
如果想知道每??值?应的数量??少,?要做?下简单的减法运算?/p>
假?想知道列值等?的个数,那么?通过?/p>
9995-4=9991得到。这就是ENDPOINT_NUMBER??值的??/p>
在看看等高直方图的情况??/p>
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'SCOTT',
TABNAME => 'TAB',
CASCADE => TRUE,
METHOD_OPT => 'FOR COLUMNS B SIZE 8 ');
END;
由于列B?0??值,通过上面的size 8?强制ORACLE使用等高直方图??/p>
查看直方图信?
SQL>SELECT TABLE_NAME, COLUMN_NAME, ENDPOINT_NUMBER, ENDPOINT_VALUE FROM USER_TAB_HISTOGRAMS
WHERE TABLE_NAME = 'TAB'?/p>
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE
------------------------------ ---------------------------------------- --------------- --------------
TAB B 0 1
TAB B 7 5
TAB B 8 10000
从查询结果惊奇的发现?三个? 7 8,原?RACLE会自动省去EDNPOINT_VALUE值相同且ENDPOINT_NUMBER相邻的桶的???/p>
省去了桶(EDNPOINT_NUMBER)为1 2 3 4 5 6 ,EDNPOINT_VALUE?的六条内容??/p>
说明:在等高直方图中,EDNPOINT_NUMBER代表桶号,这一点与等?直方图不同??/p>
再看等高直方图下的执行?划:
SQL> select * from tab where b=5;
已?择9991行??/p>
执?计划
----------------------------------------------------------
Plan hash value: 1995730731
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9982 | 59892 | 6 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TAB | 9982 | 59892 | 6 (0)| 00:00:01 |
--------------------------------------------------------------------------
有没有发现什么?
执?计划的ROWS部分,ORACLE计算出来的cardinality不是特别精确的??991才是精确值??等频直方图?精确?991,因此可以?等?直方图比等高直方图稳定,精确?/p>
?现实很?时?,列的?值是超过254的?只能使用等高直方图了??/p>