ORA-600 [KQL_TAB_DIANANEW DEP]异常的分析及处理过程
1、错误说明
数据库环境是11.2.0.3 on Windows,在创建触发器时报了如下错误:
对于这种00600的内部错误,最好的办法就是在MOS(my oracle support)上查询是否属于bug(Bug 22247534:ALTER TRIGGER FAILS WITH ORA-600 [KQL_TAB_DIANA:NEW DEP])。我的MOS客户号已过期,在求助网友之后,帮我查到这的确是该版本的一个bug,如下图:
但很不幸:没有Workaround,且Windows平台下没有补丁。虽然在下一个版本11.2.0.4中该bug已修复,但更换数据库版本在客户处有其他的麻烦。我只能尝试看是否能绕开该bug。
2、错误分析
回到上图的错误描述上:
"Missing dependency$ entries due to execution of ...DISASSOCIATE_FRA",
即由于执行DBMS_FLASHBACK_ARCHIVE.DISASSOCIATE_FRA(),导致dependency$ 中缺少了必要的条目信息。
dependency$是oracle的核心字典表,记录了各个对象对其它对象的依赖关系,该表一般通过dba_dependencies视图向用户提供信息。
我们来看一下,对表T执行DBMS_FLASHBACK_ARCHIVE.DISASSOCIATE_FRA()前后,表T在dependency$表中的条目有什么变化?
1)执行DBMS_FLASHBACK_ARCHIVE.DISASSOCIATE_FRA前:
A. 查看表T的结构
B.查看表T的flashback archive 历史表
C.查询表T及flashback archive历史表的OBJECT_ID
D.查看表T及flashback archive历史表在dependency$表中的条目
2)执行DBMS_FLASHBACK_ARCHIVE.DISASSOCIATE_FRA后:
E.执行DBMS_FLASHBACK_ARCHIVE. DISASSOCIATE_FBA:
F.查看表T及flashback archive历史表在dependency$表中的条目
小结:11.2.0.3的ORACLE,DBMS_FLASHBACK_ARCHIVE. DISASSOCIATE_FBA方法存在bug,会导致dependency$表中的条目被删除。这里抛出一个问题:DISASSOCIATE_FBA会导致dependency$表中的条目被删除,那么REASSOCIATE_FBA也同样存在这个问题吗?经验证,答案是肯定的,REASSOCIATE_FBA也会导致dependency$表中的条目被删除。
3、解决办法
错误原因搞清楚了,接下来就是思考如何解决问题。
既然DISASSOCIATE_FBA会删除dependency$表中的条目,那么可否在执行DISASSOCIATE_FBA之前先把dependency$表的条目备份出来,等DISASSOCIATE_FBA执行后,再把备份出来的条目插入到dependency$表呢?
创建一个PACKAGE,在PACKAGE中定义如下存储过程:
现在我们用DISABLE_FLAR取代DISASSOCIATE_FBA,用ENABLE_FLAR取代REASSOCIATE_FBA。理论上已经没有问题了,但实际使用过程中发现:对部分表可行,但另一部分不可行。
为什么呢?
……
经过分析发现:flashback archive 历史表的创建有延迟,它并非是在执行"Alter table x flashback archive xxxx"命令后立刻创建的。我们来验证一下:
1)新建表T,并为表T开启flashback archive
开启flashback archive仅仅是明确了flashback archive 历史表的名称,但flashback archive 历史表尚未创建,因为尚未创建,所以没法获取flashback archive 历史表的OBJECT_ID(即上图的SYS_FBA_HIST_93853),存储过程Dependency_records也就仅能获取到表T的dependency$条目,无法获取到flashback archive 历史表的dependency$条目。
经过测试,即使在表T上执行DML、开启事务,依旧不会立刻生成flashback archive 历史表,都会有时间延迟,而这个延迟时间又是不确定的。但是,如果对表T执行RENAME操作,会立刻生成flashback archive 历史表。我们来验证:
2)执行RENAME操作,并查看flashback archive 历史表是否生成
小结:执行rename操作会立刻创建flashback archive 历史表。
现在我们知道rename操作会立刻创建flashback archive 历史表,避免存储过程Dependency_records因为捕获不到flashback archive 历史表的OBJECT_ID而产生备份条目缺失的情况。如何改造存储过程呢?其实就很简单了,对Dependency_records作如下改造就可以了:
现在,使用DISABLE_FLAR来替代DISASSOCIATE_FBA,创建触发器就不再报错了。
4、总结
1)ORA-600 [KQL_TAB_DIANA:NEW DEP]可能是由于bug 22247534引起的,它会导致创建触发器失败。而失败的原因是DISASSOCIATE_FBA方法把表以及flashback archive历史表在dependency$中的条目清空了;
2)Alter table x flashback archive xxxx命令并不会立刻创建flashback archive历史表,若希望立刻创建flashback archive历史表,可以执行rename命令;
3)可以通过在DISASSOCIATE_FBA方法前后分别加上备份和还原dependency$条目的逻辑,绕开上述bug。