一个执行计划异常变更的案例 - 外传之直方图

简介: 今天单位值班,有一些时间可以继续完成这篇连载文章。首先祝所有朋友新年快乐!感谢你们在这一年当中对我文章的关注和指点,来年我们共同继续努力!之前的几篇文章: 《一个执行计划异常变更的案例...

今天单位值班,有一些时间可以继续完成这篇连载文章。首先祝所有朋友新年快乐!感谢你们在这一年当中对我文章的关注和指点,来年我们共同继续努力!

之前的几篇文章:
《一个执行计划异常变更的案例 - 前传》
《一个执行计划异常变更的案例 - 外传之绑定变量窥探》
《一个执行计划异常变更的案例 - 外传之查看绑定变量值的几种方法》
《一个执行计划异常变更的案例 - 外传之rolling invalidation》
《一个执行计划异常变更的案例 - 外传之聚簇因子(Clustering Factor)》
《一个执行计划异常变更的案例 - 外传之查询执行计划的几种方法》
《一个执行计划异常变更的案例 - 外传之AWR》
《一个执行计划异常变更的案例 - 外传之ASH》
《一个执行计划异常变更的案例 - 外传之SQL AWR》

这篇文章我们聊聊直方图。

首先我们看下统计学中对直方图的定义:

直方图(Histogram)又称质量分布图。是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况。 一般用横轴表示数据类型,纵轴表示分布情况。

可以看出,直方图可以用来描述数据分布的情况。Oracle中也是如此,直方图可以准确预测列数据的分布,尤其在出现数据分布倾斜的情况下,通过直方图信息,可以选择最优的执行计划。

P.S. 关于直方图的介绍,推荐dbsnake的书,其中第五章详细介绍了11g的直方图,非常详细受用。

11g下有两种类型的直方图(12c又多了其他类型的直方图):
Height-Balanced Histograms
Frequency Histograms
查询USER/DBA_TAB_COL_STATISTICS视图的HISTGRAM列可以知道存储的是何种类型的直方图(取值为HEIGHT BALANCED,FREQUENCY,NONE)。

创建测试表,name列有100000行值为A,1行值为B,数据出现了倾斜,name列存在非唯一二叉树索引,采集统计信息时不收集直方图,
这里写图片描述

从HISTGRAM列可以看出未有任何直方图统计,
这里写图片描述

根据name=’A’检索,选择了全表扫描的执行计划,
这里写图片描述

根据name=’B’检索,同样选择了全表扫描的执行计划,
这里写图片描述

从数据分布看,A的记录有100000条,B的记录有1条,该列有索引,按说A为条件的SQL应该选择全表扫描采用多块读的方式最高效,B为条件的SQL应该使用索引采用索引扫描的方式最高效,但实际情况是两者均采用了全表扫描的执行计划。

原因就是此时Oracle认为name列值是均匀分布的,根据Cardinality的计算,

Computed Cardinality = Original Cardinality * Selectivity
Selectivity= 1 / NUM_DISTINCT

计算如下:

Computed Cardinality = 100001 * 1 / 2

约等于50001,可以从上面两个执行计划中Rows预估行看出两个SQL的预估行均为50001。

接着我们收集name列的直方图,此处未指定method_opt会由Oracle自行来判断收集的直方图信息和类型,
这里写图片描述

可以看出name列采集了FREQUENCY类型的直方图信息,
这里写图片描述

我们再执行刚才的两条SQL,name=’A’的仍选择了全表扫描,我们要重点看下B的SQL,此时选择了索引范围扫描,不是全表扫描了,说明Oracle知道了这列的数据分布,CBO认为索引扫描成本值更低,从10053事件可以查看具体计算值,
这里写图片描述
但有一处要注意,就是Rows这是18,我们之前知道name=’B’只有1条记录,怀疑这和采用默认的统计信息收集比率有关,默认未必采用了100%的数据作为样本,重新以100%的比例采集统计信息,
这里写图片描述
可以看出Rows是1了,说明Oracle此时已经知道了数据的分布,CBO计算时知道使用索引扫描成本值更低了。

Oracle直方图使用一种称为Bucket(桶)的方式来描述列的数据分布,每个Bucket就是一组,其中会存储一个或多个列数据,Bucket使用ENDPOINT NUMBER和ENDPOINT VALUE两个维度来描述,其中ENDPOINT VALUE记录列的distinct值,ENDPOINT NUMBER表示到此distinct值为止总计有多少条记录(即这条distinct值对应的ENDPOINT NUMBER减上条记录distinct值对应的ENDPOINT NUMBER就会是这条distinct值的记录数),上面示例中name列是FREQUENCY类型的直方图,对于这种类型的直方图,Bucket的数量就是列distinct值的数量,从NUM_DISTINCT知道有2个distinct值,
这里写图片描述

因此user_tab_histograms中列name对应的记录(Bucket)应该是2条,
这里写图片描述

我们看出第一条记录:
ENDPOINT VALUE:337499295804764000000000000000000000
ENDPOINT NUMBER:100000
第二条记录:
ENDPOINT VALUE:342691592663299000000000000000000000
ENDPOINT NUMBER:100001

上面说ENDPOINT VALUE是distinct值,我们看下如何推导出,以A为例,A对应的十六进制是0x41,将0x41右补至15个字节长度的0,再将其转换为十进制,即3.3750E+35,正如上面对应的第一条记录ENDPOINT VALUE值,
这里写图片描述
第一条记录的ENDPOINT NUMBER是100000,说明有100000条记录值是A,第二条记录的ENDPOINT NUMBER是100001,说明有(100001-10000=1)条记录值是B。

对于这种FREQUENCY的直方图,dbsnake书中明确说明了其缺点,就是适合于一些distinct值少的情况,因为11g的FREQUENCY直方图对应的Bucket数量不能超过254(12c不受此限制),如果列值distinct值超过254,则不能使用这种类型的直方图。而且若列值类型是文本型,采集直方图时只会采集文本值头32个字节,换句话说,若多个列值distinct的头32个字节相同,则Oracle可能会将他们作为一个值来采集,就会对采集结果产生影响,这是错误。

对于列值distinct超过254的情况,Oracle会采集HEIGHT BALANCED类型的直方图。这种类型的直方图首先会根据列的所有记录按从小到大的顺序排序,用总记录数处于需要使用的Bucket数量,决定每一个Bucket中要存储的记录数,对于相邻Bucket的仅ENDPOINT NUMBER不同,ENDPOINT VALUE值相同记录数做合并存储,ENDPOINT VALUE存储的是到此记录所描述的Bucket为止之前所有Bucket描述的记录中列的最大值,通过实验我们体会下,创建测试数据,
这里写图片描述
name列有301个distinct值,其中值为201有700条记录,采集统计信息时指定Bucket数量是10,此时查看user_tab_col_statistics的HISTOGRAM值变为了HEIGHT BALANCED,
这里写图片描述

select 1000/10 from dual;

知道每一个Bucket应该存储100条记录数,
这里写图片描述
0号Bucket存储的是列最小值,即1,1-10号Bucket存储的是到此记录所描述的Bucket位置之前所有Bucket描述的记录中列的最大值,每个Bucket存储100条记录数,因此这可以推测出1号Bucket的ENDPOINT VALUE是之前存储的最大值100,ENDPOINT NUMBER是1-0=1,因为每一个distinct这只有一条,值为201的记录有700条,一个Bucket不足以存储,需要7个Bucket,从顺序上看,是2号至9号,由于这几个Bucket的ENDPOINT NUMBER不同,ENDPOINT VALUE值相同,因此做了合并,这种合并后的ENDPOINT VALUE称为popular value,该值记录的ENDPOINT NUMBER和上一记录的ENDPOINT NUMBER差值越大,则意味着这个popular value在表中所占比例也就越大,对应的Cardinality就越大了,进而影响执行计划的成本计算。

此时我们根据name=201执行,选择了全表扫描的执行计划,
这里写图片描述

根据name=1执行,此时选择了索引扫描的执行计划,
这里写图片描述

对于这种distinctr超过254的情况,HEIGHT BALANCED用这种方式存储了直方图信息,计算成本时参考,因此选择了正确的执行计划。

总结:
直方图描述了列的数据分布情况,对于列值数据分布倾斜的表,使用直方图可以帮助选择正确的执行计划,11g有两种直方图类型,FREQUENCY和HEIGHT BALANCED,其中FREQUENCY适合于distinct不超过254的表,而且有错误预测的可能。HEIGHT BALANCED采用这种popular value的合并方式来存储直方图信息且对执行计划Cardinality的预测提供参考依据。

目录
相关文章
|
Shell Linux Ubuntu
解决在SecurecCRT登录后,发现方向键、backspace(退格键)、delete(删除键)为乱码的问题
问题:使用securecrt ssh到linux之后,backspace(退格键),delete(删除键),以及4个方向键都为乱码,不能正常使用。按tab键也没有自动补全文件名。 即: 按Backspace(退格键)和delete(删除键)屏幕显示的是:^H 按方向键则屏幕显示的是:^[[A^[[B^[[C^[[D 环境: SecureCRT8.
4264 0
|
SQL OceanBase
obdumper` 工具
obdumper` 工具
677 1
|
SQL 存储 Oracle
Oracle之3种表连接方式(排序合并连接、嵌套循环、哈希连接)
Oracle之3种表连接方式(排序合并连接、嵌套循环、哈希连接) 排序合并连接 1.2.4.2.1  排序合并连接 排序合并连接(Sort Merge Join)是一种两个表在做表连接时用排序操作(Sort)和合并操作(Merge)来得到连接结果集的表连接方法。
3649 0
|
SQL 分布式计算 DataWorks
GDB 数据导入| 学习笔记
快速学习 GDB 数据导入。
GDB 数据导入| 学习笔记
|
索引 测试技术 SQL
对象迁移表空间引出的三个小问题
我们有一个开发库,默认表空间是TEST_TBS,但今天查看开发库的时候,发现有些表和字段并不在用户默认使用的表空间中,而在USERS表空间,之所以可能是之前开发人员执行SQL是从其他库复制过来的,连通tablespace USERS名称一块复制了,为了规范,就需要将这些对象转移下表空间,期间碰见了几个常见的小问题,值得记录一下。
867 0
|
SQL Oracle 网络协议
手工搭建Data Guard
Data Guard的搭建可以使用GC图形化安装,优缺点很明显,优点就是图形化操作,符合国人的习惯(据secooler介绍外国程序员能用图形化做的事就一定用图形做,因为boss看得懂,和国人正相反。
770 0
使用exp导出报错EXP-00091
使用如下命令执行导出操作: exp user/pwd@db file=/home/a.dmp log=/home/a.
976 0
|
SQL Oracle 关系型数据库
灌入大量数据后手工采集统计信息的重要性
1. 创建测试表TBL_STAT,及索引,但不插入记录 SQL> create table TBL_STAT as select * from dba_objects where 11; Table created.
583 0
|
关系型数据库 Oracle 测试技术
exp/imp碰到的两则问题处理(ORA-00904和the objects were exported by ABC not by you)
最近负责搭建某系统的用户环境,其中涉及从测试环境导入数据,由于受客观因素制约,不能使用传输表空间方法同步,因此需要用imp/exp或数据泵的方法,这里采用的是imp/exp。
1441 0
|
SQL 监控
相同更改数据量的前提下,单次COMMIT和多次COMMIT对日志空间浪费的影响对比
LGWR进程按照顺序写在线日志,中间不会跳跃,而且LGWR进程不会在同一个日志快写2次,即使一次写入的日志快只占几个字节,下次不会再用了,这就造成日志空间的浪费。
690 0