分类:
2008-10-16 19:10:13
在报表数据库的后台alert文件中发现了这个错误,简单记录一下问题的诊断和解决过程。数据库版本9204 for Solaris sparc64。
寻找产生问题的真正原因。
在第一篇文章中,定位了问题并且找到了解决方法;在第二篇文章中,找到了导致源数据库和目标数据库执行计划不同的原因。
但是到目前为止,还没有找到这个问题产生的真正原因。
首先理一下思路,根据第一篇文章的描述,产生ORA-4030问题的原因是由于一个大数据量的插入语句选择了一个十分糟糕的执行计划。而导致选择了这个执行计划的直接原因是由于列的统计信息出现了错误。而在第二篇文章中,可以确认由于源数据库的版本为9201,没有使用列统计信息中的DENSITY列,所以没有引发这个问题。而在目标数据库版本为9204,使用了统计信息列DENSITY的值,所以Oracle认为访问ORD_HIT_COMM表且通过ENABLE_FLAG列进行限制,只会返回1条记录,这就导致了Oracle产生了一个错误的离谱的执行计划。
现在的问题是什么导致了源数据库错误统计信息的产生。
这就需要检查源数据库数据和统计的来源。因为在源数据库9201上直接收集统计信息,是不会得到这种DENSITY的。
经过检查发现这个9201的源数据库仍然不是数据的真正源头,而真正的来源数据库版本是10203。
发现了这个信息,那么问题的产生就不奇怪了。
看一下10203上这张表的统计信息:
SQL> SELECT COLUMN_NAME, NUM_DISTINCT, NUM_NULLS, DENSITY, NUM_BUCKETS, HISTOGRAM 2 FROM USER_TAB_COLUMNS 3 WHERE TABLE_NAME = 'ORD_HIT_COMM' 4 AND COLUMN_NAME = 'ENABLE_FLAG'; COLUMN_NAME NUM_DISTINCT NUM_NULLS DENSITY NUM_BUCKETS HISTOGRAM ------------ ------------ ---------- ---------- ----------- --------------- ENABLE_FLAG 2 0 2.8355E-07 2 FREQUENCY |
可以看到,在Oracle10g使用了BUCKETS的设置,而且USER_TAB_COLUMNS添加了一个字段HISTOGRAM用来表示列的统计信息的类型。
FREQUENCY类型和以往的HEIGHT BALANCED类似的列统计不同。使用FREQUENCY类型,Oracle会选择与NUM_DISTINCT相同数量的NUM_BUCKETS来进行直方图统计,而直方图统计信息方式和基于高度的统计信息是不同的。最关键的是,这种统计方式的DENSITY的结果和HEIGHT BALANCED的计算方式大不相同。
因此在10g中,由于Oracle了解当前列的统计信息方式为FREQUENCY类型,因此可以根据直方图的信息得到正确的执行计划和返回记录数:
SQL> SELECT COLUMN_NAME, NUM_DISTINCT, NUM_NULLS, DENSITY, NUM_BUCKETS, HISTOGRAM 2 FROM USER_TAB_COLUMNS 3 WHERE TABLE_NAME = 'ORD_HIT_COMM' 4 AND COLUMN_NAME = 'ENABLE_FLAG'; COLUMN_NAME NUM_DISTINCT NUM_NULLS DENSITY NUM_BUCKETS HISTOGRAM ------------ ------------ ---------- ---------- ----------- --------------- ENABLE_FLAG 2 0 2.8355E-07 2 FREQUENCY 1 row selected. SQL> EXPLAIN PLAN FOR 2 SELECT * FROM ORD_HIT_COMM WHERE ENABLE_FLAG = '1'; |
[1]