电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

一次ORA-4030问题诊断及解决(三)


发布日期:2023/11/8
 

在报表数据库的后台alert文件中发现了这个错误简单记录一下问题的诊断和解决过程数据库版本 for Solaris sparc

寻找产生问题的真正原因

在第一篇文章中定位了问题并且找到了解决方法;在第二篇文章中找到了导致源数据库和目标数据库执行计划不同的原因

但是到目前为止还没有找到这个问题产生的真正原因

首先理一下思路根据第一篇文章的描述产生ORA问题的原因是由于一个大数据量的插入语句选择了一个十分糟糕的执行计划而导致Oracle选择了这个执行计划的直接原因是由于列的统计信息出现了错误而在第二篇文章中可以确认由于源数据库的版本为没有使用列统计信息中的DENSITY列所以没有引发这个问题而在目标数据库版本为Oracle使用了统计信息列DENSITY的值所以Oracle认为访问ORD_HIT_COMM表且通过ENABLE_FLAG列进行限制只会返回条记录这就导致了Oracle产生了一个错误的离谱的执行计划

现在的问题是什么导致了源数据库错误统计信息的产生

这就需要检查源数据库数据和统计的来源因为在源数据库上直接收集统计信息是不会得到这种DENSITY的

经过检查发现这个的源数据库仍然不是数据的真正源头而真正的来源数据库版本是

发现了这个信息那么问题的产生就不奇怪了

看一下上这张表的统计信息

SQL>SELECTCOLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETSHISTOGRAM

FROMUSER_TAB_COLUMNS

WHERETABLE_NAME=ORD_HIT_COMM

ANDCOLUMN_NAME=ENABLE_FLAG;

COLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETSHISTOGRAM

ENABLE_FLAGEFREQUENCY

可以看到在Oracleg使用了BUCKETS的设置而且USER_TAB_COLUMNS添加了一个字段HISTOGRAM用来表示列的统计信息的类型

FREQUENCY类型和以往的HEIGHT BALANCED类似的列统计不同使用FREQUENCY类型Oracle会选择与NUM_DISTINCT相同数量的NUM_BUCKETS来进行直方图统计而直方图统计信息方式和基于高度的统计信息是不同的最关键的是这种统计方式的DENSITY的结果和HEIGHT BALANCED的计算方式大不相同

因此在g中由于Oracle了解当前列的统计信息方式为FREQUENCY类型因此可以根据直方图的信息得到正确的执行计划和返回记录数

SQL>SELECTCOLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETSHISTOGRAM

FROMUSER_TAB_COLUMNS

WHERETABLE_NAME=ORD_HIT_COMM

ANDCOLUMN_NAME=ENABLE_FLAG;

COLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETSHISTOGRAM

ENABLE_FLAGEFREQUENCY

rowselected

SQL>EXPLAINPLANFOR

SELECT*FROMORD_HIT_COMMWHEREENABLE_FLAG=;

Explained

SQL>SELECT*FROMTABLE(DBMS_XPLANDISPLAY);

PLAN_TABLE_OUTPUT

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|

||SELECTSTATEMENT||K|M|()|

||TABLEACCESSFULL|ORD_HIT_COMM|K|M|()|

rowsselected

但是如果将统计信息导入到数据库中就会存在严重的问题由于i的数据库中没有表示统计信息类型的HISTOGRAM列因此即使是基于FREQUENCY类型的统计信息也会被当作基于HEIGHT BALANCED类型的统计信息

而且从导入的统计信息可以看到虽然直方图的统计信息被导入但是USER_TAB_COLUMNS中的NUM_BUCKETS列的值为也就是说中优化器根本不会去考虑直方图信息而是直接通过NUM_DISTINCT和DENSITY的值来确定执行计划和返回记录数

对于版本Oracle都使用NUM_DISTINCT的值也就避免了问题的产生而在Oracle使用了DENSITY的值而这个值并不是版本的DBMS_STATS包生成的统计信息而是从g环境中导入的且这个值在g的FREQUENCY类型的统计信息中已经改变了计算方法使得计算结果比环境中要小得多从而导致了上错误执行计划的产生

显然整个问题完全是由于版本差异造成的这个问题说明在将g的表导入到环境中最好不要导入统计信息

在导出阶段或在导入阶段设置STATISTICS = NONE避免g的统计信息导入到环境中在导入过程结束后手工在环境上重新收集统计信息

一旦g的统计信息被导入到环境中就必须重新收集统计信息

SQL>SELECT*FROMV$VERSION;

BANNER

OracleiEnterpriseEditionReleasebitProductionPL/SQLReleaseProduction

COREProduction

TNSforLinux:VersionProduction

NLSRTLVersionProduction

SQL>SELECTCOLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETS

FROMUSER_TAB_COLUMNS

WHERETABLE_NAME=ORD_HIT_COMM

ANDCOLUMN_NAME=ENABLE_FLAG;

COLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETS

ENABLE_FLAGE

SQL>EXPLAINPLANFOR

SELECT*FROMORD_HIT_COMMWHEREENABLE_FLAG=;

已解释

SQL>SELECT*FROMTABLE(DBMS_XPLANDISPLAY);

PLAN_TABLE_OUTPUT

|Id|Operation|Name|Rows|Bytes|Cost|

||SELECTSTATEMENT|||||

|*|TABLEACCESSFULL|ORD_HIT_COMM||||

PredicateInformation(identifiedbyoperationid):

filter(ORD_HIT_COMMENABLE_FLAG=)

Note:cpucostingisoff

已选择

这时g的统计信息已经导入到环境中如果忘记重新收集统计信息就会导致这个错误的产生

SQL>EXECDBMS_STATSGATHER_TABLE_STATS(USERORD_HIT_COMM)

PL/SQL 过程已成功完成

SQL>SELECTCOLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETS

FROMUSER_TAB_COLUMNS

WHERETABLE_NAME=ORD_HIT_COMM

ANDCOLUMN_NAME=ENABLE_FLAG;

COLUMN_NAMENUM_DISTINCTNUM_NULLSDENSITYNUM_BUCKETS

ENABLE_FLAG

SQL>EXPLAINPLANFOR

SELECT*FROMORD_HIT_COMMWHEREENABLE_FLAG=;

已解释

SQL>SELECT*FROMTABLE(DBMS_XPLANDISPLAY);

PLAN_TABLE_OUTPUT

|Id|Operation|Name|Rows|Bytes|Cost|

||SELECTSTATEMENT||K|M||

|*|TABLEACCESSFULL|ORD_HIT_COMM|K|M||

PredicateInformation(identifiedbyoperationid):

filter(ORD_HIT_COMMENABLE_FLAG=)

Note:cpucostingisoff

已选择

这个问题也从另一个角度说明进行跨版本迁移测试工作的重要性

上一篇:Xft字体库:体系结构及用户指南

下一篇:邮件管理篇 VmailMgr