µ±ǰλÖ㺠´úÂëÃÔ >> Êý¾ݿâ >> ORACLE Histograms (直方å›
  Ïêϸ½â¾ö·½°¸

ORACLE Histograms (直方å›

Èȶȣº5124   ·¢²¼ʱ¼䣺2013-02-26 00:00:00.0
ORACLE Histograms (直方å›?

ä¸?.何谓直方图:

直方图是ä¸?种统计å?上的工具,并非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>

  Ïà¹ؽâ¾ö·½°¸