查看: 8389|回复: 15

[FAQ] ORACLE的直方图的一些试验

[复制链接]
论坛徽章:
21
奔驰
日期:2013-08-06 15:23:05日产
日期:2013-08-07 22:56:38蜘蛛蛋
日期:2012-12-29 19:15:08奥迪
日期:2013-08-07 17:02:24数据库板块每日发贴之星
日期:2010-06-28 01:01:03奥迪
日期:2013-08-13 10:10:28本田
日期:2013-11-20 15:17:02优秀写手
日期:2013-12-18 09:29:08玉兔
日期:2014-03-04 16:47:17铁扇公主
日期:2012-02-21 15:02:40
跳转到指定楼层
1#
发表于 2010-5-8 13:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

直方图有两种类别,等频直方图与等高直方图。
默认的,如果一个倾斜列上的唯一值超过了254个,那么ORACLE会对此列建立等高直方图,否则建立等频直方图。
通过如下方式,建立表TAB,更新字段B,让列B产生倾斜。并在B列上创建索引。
SQL> spool d:\hist.txt
SQL> create table tab (a number, b number);

表已创建。

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 过程已成功完成。

SQL> update tab set b=5 where b between 6 and 9995;

已更新9990行。
SQL> commit;

提交完成。

SQL> create index ix_tab_b on tab(b);

索引已创建。


然后分析表,强制使列B不产生直方图。
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)0和1,这种显示说明列B没有直方图信息。
SQL>SELECT table_name,column_name,endpoint_number,endpoint_value FROM USER_TAB_HISTOGRAMS WHERE TABLE_NAME='TAB' ;

TABLE_NAME                     COLUMN_NAME                              ENDPOINT_NUMBER ENDPOINT_VALUE
------------------------------ ---------------------------------------- --------------- --------------
TAB                            B                                                      0              1
TAB                            B                                                      1          10000

在没有直方图的情况下,在B列上进行等值查询的时候,都是索引范围扫描。

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行。


执行计划
----------------------------------------------------------
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 |
----------------------------------------------------------------------------------------


[ 本帖最后由 wei-xh 于 2010-5-8 14:12 编辑 ]
论坛徽章:
21
奔驰
日期:2013-08-06 15:23:05日产
日期:2013-08-07 22:56:38蜘蛛蛋
日期:2012-12-29 19:15:08奥迪
日期:2013-08-07 17:02:24数据库板块每日发贴之星
日期:2010-06-28 01:01:03奥迪
日期:2013-08-13 10:10:28本田
日期:2013-11-20 15:17:02优秀写手
日期:2013-12-18 09:29:08玉兔
日期:2014-03-04 16:47:17铁扇公主
日期:2012-02-21 15:02:40
2#
 楼主| 发表于 2010-5-8 13:33 | 只看该作者
收集直方图信息。看看是什么效果。由于列B唯一值的个数没有超过254因此产生的是等频直方图。
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(OWNNAME    => 'SCOTT',
                                TABNAME    => 'TAB',
                                CASCADE    => TRUE,
                                METHOD_OPT => 'FOR ALL COLUMNS  SIZE AUTO ');
END;

在B=1时候采用索引扫描,而B=5时候,已经采用全表扫描了,说明直方图起了作用。
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行。


执行计划
----------------------------------------------------------
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 |
--------------------------------------------------------------------------




查看此时的直方图信息:
SQL>SELECT TABLE_NAME, COLUMN_NAME, ENDPOINT_NUMBER, ENDPOINT_VALUE FROM USER_TAB_HISTOGRAMS
WHERE TABLE_NAME = 'TAB';

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是9991,和实际的情况完全吻合。
如果想知道每一个列值对应的数量是多少,需要做一下简单的减法运算:

假如想知道列值等于5的个数,那么可以通过:
9995-4=9991得到。这就是ENDPOINT_NUMBER累计值的含义。


[ 本帖最后由 wei-xh 于 2010-5-8 13:56 编辑 ]

使用道具 举报

回复
论坛徽章:
21
奔驰
日期:2013-08-06 15:23:05日产
日期:2013-08-07 22:56:38蜘蛛蛋
日期:2012-12-29 19:15:08奥迪
日期:2013-08-07 17:02:24数据库板块每日发贴之星
日期:2010-06-28 01:01:03奥迪
日期:2013-08-13 10:10:28本田
日期:2013-11-20 15:17:02优秀写手
日期:2013-12-18 09:29:08玉兔
日期:2014-03-04 16:47:17铁扇公主
日期:2012-02-21 15:02:40
3#
 楼主| 发表于 2010-5-8 14:08 | 只看该作者
在看看等高直方图的情况。
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(OWNNAME    => 'SCOTT',
                                TABNAME    => 'TAB',
                                CASCADE    => TRUE,
                                METHOD_OPT => 'FOR  COLUMNS B SIZE 8 ');
END;

由于列B有10个唯一值,通过上面的size 8可以强制ORACLE使用等高直方图。
查看直方图信息.
SQL>SELECT TABLE_NAME, COLUMN_NAME, ENDPOINT_NUMBER, ENDPOINT_VALUE FROM USER_TAB_HISTOGRAMS
WHERE TABLE_NAME = 'TAB';

TABLE_NAME                     COLUMN_NAME                              ENDPOINT_NUMBER ENDPOINT_VALUE
------------------------------ ---------------------------------------- --------------- --------------
TAB                            B                                                      0              1
TAB                            B                                                      7              5
TAB                            B                                                      8          10000

从查询结果惊奇的发现只有三个桶0 7 8,原来ORACLE会自动省去EDNPOINT_VALUE值相同且ENDPOINT_NUMBER相邻的桶的值。

省去了桶(EDNPOINT_NUMBER)为1 2 3 4 5 6 ,EDNPOINT_VALUE为5的六条内容。


说明:在等高直方图中,EDNPOINT_NUMBER代表桶号,这一点与等频直方图不同。

再看等高直方图下的执行计划:

SQL> select * from tab where b=5;
已选择9991行。

执行计划
----------------------------------------------------------
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不是特别精确的。9991才是精确值。而等频直方图可以精确到9991,因此可以说等频直方图比等高直方图稳定,精确。
可是现实很多时候,列的唯一值是超过254的。只能使用等高直方图了。


[ 本帖最后由 wei-xh 于 2010-5-8 22:35 编辑 ]

使用道具 举报

回复
论坛徽章:
0
4#
发表于 2010-5-8 19:28 | 只看该作者
good share

使用道具 举报

回复
论坛徽章:
0
5#
发表于 2010-5-10 12:46 | 只看该作者
thanks ,good!

使用道具 举报

回复
论坛徽章:
6
在线时间
日期:2007-05-20 04:01:01授权会员
日期:2007-06-01 08:14:30会员2007贡献徽章
日期:2007-09-26 18:42:10ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512012新春纪念徽章
日期:2012-01-04 11:51:22
6#
发表于 2010-10-24 00:39 | 只看该作者
不错

使用道具 举报

回复
论坛徽章:
86
2015中国数据库技术大会纪念徽章
日期:2015-04-24 16:04:24马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11优秀写手
日期:2013-12-18 09:29:11日产
日期:2013-10-17 08:44:39马自达
日期:2013-08-26 16:28:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:51马上有房
日期:2014-02-19 11:55:14
7#
发表于 2010-10-25 08:50 | 只看该作者
nice job

使用道具 举报

回复
论坛徽章:
0
8#
发表于 2011-3-14 17:27 | 只看该作者
请教一下:

1. 如果列B有新的数据插入或者更新,直方图会随之更新吗?
2. 在列B上建位图索引能否解决同样的问题?

使用道具 举报

回复
论坛徽章:
0
9#
发表于 2011-3-31 11:26 | 只看该作者

疑问

在9i(9.2.0.6.0)中试验是没有问题,10.2.0.4中在建立直方图后,还是使用索引,请问哪位知道是为什么?

使用道具 举报

回复
论坛徽章:
47
蒙奇·D·路飞
日期:2017-03-27 08:04:23马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11一汽
日期:2013-09-01 20:46:27复活蛋
日期:2013-03-13 07:55:232013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:03:322012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20
10#
发表于 2011-3-31 22:06 | 只看该作者
本帖最后由 Yong Huang 于 2012-3-22 08:58 编辑

> 1. 如果列B有新的数据插入或者更新,直方图会随之更新吗?

It won't automatically. You have to manually gather stats again. Your DB may have a nightly job to do it too.

> 2. 在列B上建位图索引能否解决同样的问题?

A bitmap index? Why do you think so?

> 10.2.0.4中在建立直方图后,还是使用索引,请问哪位知道是为什么?

Can you show us the sqlplus screen (text, not image)? I'd like to reproduce on my end.

Yong Huang

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表