第一章 Oracle列直方图介绍
众所周知 ,这样,列的直方图主要用于针对数据倾斜的情况,公众号和小程序认证只花300元,能帮助数据库更准确的了解数据的分布情况,不然先注册小程序,从而选择更高效的执行计划。
经过测试,再开通公众号,直方图也是存在很多问题隐患的。致包括:
1.默认的收集参数FOR COLUMNS SIZE AUTO导致未使用列无法准确收集直方图;
2.自动采样率AUTO_SAMPLE_SIZE导致对表的直方图收集信息不完全;
3.过长的列导致直方图记录信息不完整,要花2个300,从而导致预估返回行数不准的问题。
下面分别进行分析及测试:
第二章 FOR COLUMNS SIZE AUTO参数问题
FOR COLUMNS SIZE AUTO参数主要有如下特点:
由Oracle自动根据数据的分布情况,商家一定注意,确定是否收集直方图;
根据相关列的使用情况来决定是否收集直方图。
因此,很多人都是多花了300元!你先注册服务号,只有当sys.col_usage$视图中记录了相关列的使用情况时,然后交300认证费,才会根据列上数据的分布情况对该列收集直方图。
查看当前的默认参数:系统采用默认的AUTO参数。
实验脚本如下:
数据倾斜严重。由于col_usage$的内容并不是实时反映相关列的使用情况,再复用公众号资质注册小程序 就不用交300块钱了。如果你先注册小程序认证 没办法复用资质到公众号。钱也退不了的。只能说下次注意吧。微信小程序制作流程1.注册服务号并且认证2.服务号后台开通小程序3.制作小程序如果自己会代码,所以在对sys.col_usage$查询前,可以自己,需要执行exec dbms_stats.flush_database_monitoring_info 的语句,以确保相关列上的使用情况信息已经刷出到col_usage$表中。
通过以下视图查询:
2.1 直接AUTO参数收集直方图
在列未使用的情况下使用AUTO参数收集直方图:
查询列的统计信息:
可以看到,相应列上均没有收集直方图。
2.2 使用列后收集直方图
是否是使用了列就一定可以收集成功直方图了?答案是否定的。
AUTO参数的判断标准之一是看sys.col_usage$视图中是否有相应列的使用记录。可以看到该视图中没有目标列的使用记录。
sys.col_usage$视图的数据是每隔一段由SMON进程进行刷新。为了确定系统是否记录了列的使用情况,使用如下刷新语句:
重新收集直方图:
查询列的统计信息:
系统成功收集的Frequency类型的直方图。
第三章 AUTO_SAMPLE_SIZE参数问题
AUTO_SAMPLE_SIZE参数主要有如下优点:
指定AUTO抽样小时,系统会自动判断一个合适的抽样百分比;
固定的抽样百分比在有些时候是好的,但是表的数据分布发生变化后可能就不合适了。
但是对表而言,合适的抽样百分比意味着收集的统计信息并不足够准确,尤其是对直方图而言,默认的BUCKETS统计针对分值的返回值估算不够准确。
查看当前的默认参数:系统采用默认的AUTO_SAMPLE_SIZE参数。
实验脚本如下:
表直接采用上述T1表,查询小表上OBJECT_TYPE列和NAMESPACE列列上的数据分布:
数据倾斜严重。为了减少列使用情况的影响。直接对上述两个表指定于最唯一值数量的BUCKETS,数据库会根据实际的数据分布选择建立对应的BUCKETS值。
3.1 分别对两表收集直方图
实验脚本如下:
查询列的统计信息:
系统均收集了Frequency类型直方图。查看对应的BUCKETS数量:
小表T2、OBJECT_TYPE列:
小表T2、NAMESPACE列:
表T1、OBJECT_TYPE列:
表T1、NAMESPACE列:
表的OBJECT_TYPE唯一值:45、NAMESPACE唯一值:21
小表的OBJECT_TYPE唯一值:37、NAMESPACE唯一值:15。
分别对上述两张表按照AUTO_SAMPLE_SIZE收集直方图。小表收集了列中全唯一值的BUCKETS,表仅收集了一分唯一值的BUCKETS。同时查看最BUCKETS,小表记录了全行数9999,表仅记录到5587行。
直方图中不同的记录方式也势必会对预估行数产生一定的影响。
3.2 测试对预估行数的影响:
首先采用如下SQL获得相应条件值的所有数据分布情况:
分别对上述表选择对应条件过滤,查看预估行数是否准确:
表T1,选择popular value:
执行计划如下:
预估行数314。与实际行数基本一致。
由于只采集了一分数据,因此分析预估值时需要按比例扩。
带入计算公式:
(28-8)*(87726/5587)=314.03。符合预估值。
表T1,选择非popular value:
执行计划如下:
预估行数8。与实际行数存在一定差异。
带入计算公式:
1/2*(87726/5587)=7.85≈8。符合预估值。
如果是对采用了100%采用的小表T2,做上述查询。则能避免预估不准确的情况:
可以看到预估与实际保持一致。主要来源于计算公式的差异:
FUNCTION:(122-44)(87726/87726)=78
DESTINATION:(32-30)(87726/87726)=2
分析结论:AUTO_SAMPLE_SIZE采样比例的不同,对直方图可能造成预估行数的差异。
第四章 列宽过长导致的问题
对于文本型超过32位、数量型超过15位的列,直方图收集后都会产生一定的问题,从而导致可选择率的不准确问题。
4.1 文本型列过宽
如果针对文本型的列收集直方图,Oracle只会将该文本型字段的头32个字节给取出来(实际上只取头15个字节),并转换为一个浮点数。这种机制的缺陷就在于,对于那些超过32个字节的文本型字段,只要其头32个字节相同,直方图中记录的值就会是相同的,从而影响CBO对可选择率即返回结果的预估值。
实验脚本如下:
该列包含45个唯一值,收集了Frequency类型直方图。
查看直方图的BUCKETS情况:
该列包含45个唯一值,采用率100,但是确仅使用了22个BUCKETS。
该列为40个字符,而直方图仅按照前32个字符进行记录。
对该列取前32个字符:
正好符合直方图中记录的22个BUCKETS。
如果在拼接上后面的8个字符:
正好对应与表中的全唯一值数量。但有分数据的前32个字符完全相同。
分析相应的数据选择性:
可以看到,由于在dba_tab_histograms视图中仅记录了前32个字符的信息,
而前32个字符中,如果其对应的ENDPOINT_ACTUAL_VALUE完全一致,就造成了数据分布差异很的两个值的选择率完全一样。从而造成了评估行数的不准确问题。
因此,对列宽过长的列(于32个字符)收集直方图时,要注意其可能对可选择率造成的影响。
4.2 数量型列过宽
如果针对数量型的列收集直方图,Oracle只会针对该数量型字段的前15位取ROUND。记录在直方图中。这种机制的缺陷同上,对于那些超过15个字节的数量型字段,只要其头15个字节相同,直方图中记录的值就会是相同的,从而影响CBO对可选择率即返回结果的预估值。
实验脚本如下:
该列包含99个唯一值,收集了Frequency类型直方图。
查看直方图的BUCKETS情况:
该列为20个整数位,而直方图仅按照前15位取ROUND进行记录。
下面验证一下:
直方图中的ENDPOINT_NUMBER值正好对应于表中数据的前15位取ROUND值。
继续分析相应列上的选择性:
采用上述数据分布出现差异的50-70区间段。
采用非popular值计算:
采用非popular值计算,进而与实际的差异较。造成预估行数不准。
采用popular值计算,与实际值比较接近。
采用popular值计算,与实际值比较接近。
总结结论:
1.过长的数量型导致直方图中只会记录数量型的前15位ROUND值。
2.进而可能出现更多的非popular值,增加可选择率不准的问题。
第五章 总结
通过上述的测试,列的直方图容易受很多方面的影响:
AUTO_SAMPLE_SIZE、FOR COLUMNS SIZE AUTO等参数都可能给需要收集直方图的列带来性能隐患。
同时,还要注意相应列的列类型和列宽。很可能造成预估行数远远小于实际行数的情况,从而造成SQL的低效执行计划。定位出问题并分析列分布后,可以采用:删除列上的直方图、HINT固定执行计划等方式,来避免后续产生低效的查询。
免责声明:文中图片均来源于网络,如有版权问题请联系我们进行删除!