设为首页 加入收藏

TOP

Oracle直方图详解(一)
2017-02-28 08:15:59 】 浏览:495
Tags:Oracle 方图 详解

1 直方图的含义


看一个由于数据分布极不均衡而导致CBO选错执行计划的例子:


个由于数据分布极不均衡而导致CBO选错执行计划的例子:


zx@ORCL>create table t1 (a number(5),b varchar2(5));
?
Table created.
?
zx@ORCL>declare cnt number(5) := 1;
? 2? begin
? 3? loop
? 4? insert into t1 values(1,'1');
? 5? if cnt=10000 then
? 6? exit;
? 7? end if;
? 8? cnt:=cnt+1;
? 9? end loop;
?10? insert into t1 values(2,'2');
?11? commit;
?12? end;
?13? /
?
PL/SQL procedure successfully completed.
?
zx@ORCL>select b,count(*) from t1 group by b;
?
B? ? ? ? ? ? ? ? COUNT(*)
--------------- ----------
1? ? ? ? ? ? ? ? ? ? 10000
2? ? ? ? ? ? ? ? ? ? ? ? 1
?
zx@ORCL>create index t1_ix_b on t1(b);
?
Index created.


对表T1不收集直方图统计信息的方式收集一下统计信息:


zx@ORCL>exec dbms_stats.gather_table_stats(USER,'T1',estimate_percent=>100,method_opt=>'for all columns size 1');
?
PL/SQL procedure successfully completed.
?
zx@ORCL>select * from t1 where b='2';
?
? ? ? ? A B
---------- ---------------
? ? ? ? 2 2
?
zx@ORCL>select * from table(dbms_xplan.display_cursor(null,null,'all'));
?
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID? 5p7b772tpcvm4, child number 0
-------------------------------------
select * from t1 where b='2'
?
Plan hash value: 3617692013
?
--------------------------------------------------------------------------
| Id? | Operation? ? ? ? | Name | Rows? | Bytes | Cost (%CPU)| Time? ? |
--------------------------------------------------------------------------
|? 0 | SELECT STATEMENT? |? ? ? |? ? ? |? ? ? |? ? 7 (100)|? ? ? ? ? |
|*? 1 |? TABLE ACCESS FULL| T1? |? 5001 | 25005 |? ? 7? (0)| 00:00:01 |
--------------------------------------------------------------------------
.....省略部分输出


从执行计划可以看出执行计划走的是全表扫描,但是很显然应该走索引T1_IX_B。这是因为CBO默认认为列B的数据是均匀分布的,而列B上的distinct值只有1和2这两值,所以CBO评估出来的对列B施加等值查询条件的可选择率就是1/2,进而评估出来对列B施加等值查询条件的结果集的Cardinality就是5001:


zx@ORCL>select round(10001*(1/2)) from dual;
?
ROUND(10001*(1/2))
------------------
? ? ? ? ? ? ? 5001


正因为CBO评估出上述等值查询要返回结果集的Cardinality是5001,已经占了表T1总记录数的一半,所以CBO认为此时再走列B上的索引T1_IX_B就已经不合适了,进而就选择了对列T1的全表扫描。但实际上,CBO对上述等值查询要返回结果集的Cardinality的评估已经与事实严重不符,评估出来的值是5001,其实却只有1,差了好几个数量级。


CBO这里选择了执行计划,正确的执行计划应该是走索引T1_IX_B。CBO选错执行计划的根本原因是表T1的列B的分布实际上是极度不均衡的(列B一共就两值,其中10000个1,只有1个2),CBO在评估的一开始所用的原则就错了,当然结果也就错了。


为了解决上述问题,Oracle引入了直方图(Histogram)。直方图是一种特殊的列统计信息,它详细描述了目标列的数据分布情况。直方图实际上存储在数据字典基表HISTGRM$中,可以通过数据字典DBA_TAB_HISTOGRAMS、DBA_PART_HISTOGRAMS和DBA_SUBPART_HISTOGRAMS来分别查看表、分区表的分区和分区表的子分区的直方图统计信息。


如果对目标列收集了直方图,则意味着CBO将不再认为该目标列上的数据是均匀分布的了,CBO就会用该目标列上的直方图统计信息来计算对该列施加查询条件后的可选择率和返回结果集的Cardinality,进而据此计算成本并选择相应的执行计划。


还用上面的例子,对表T1的列B收集了直方图统计信息后,CBO正确地评估出了返回结果集的Cardinality不是5001而是1,进而就正确地选择了走索引T1_IX_B的执行计划:


zx@ORCL>exec dbms_stats.gather_table_stats(USER,'T1',estimate_percent=>100,method_opt=>'for all columns size auto',cascade=>true);
?
PL/SQL procedure successfully completed.
#清空shared_pool,生产系统不要随便执行
zx@ORCL>alter system flush shared_pool;
?
System altered.
?
zx@ORCL>select * from t1 where b='2';
?
? ? ? ? A B
---------- ---------------
? ? ? ? 2 2
?
zx@ORCL>select * from table(dbms_xplan.display_cursor(null,null,'all'));
?
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇使用Docker快速构建MySQL主从复制.. 下一篇CentOS安装MariaDB数据库(MySQL..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目