我有一个存储过程,只需启用特定表的约束。
它已经工作了很长一段时间,但突然(今天),我收到了ORA-08103错误。
导致此错误的原因是什么?
BEGIN
FOR c IN (
SELECT
c.owner,
c.table_name,
c.constraint_name
FROM user_constraints c
WHERE c.status = 'DISABLED'
AND c.table_name IN (
'TABLE_01', 'TABLE_02', 'TABLE_03', 'TABLE_04'
)) LOOP
EXECUTE IMMEDIATE 'ALTER TABLE ' || c.table_name || ' ENABLE CONSTRAINT ' || c.constraint_name;
END LOOP;
END;
[更新]
这些是我要遵循的步骤。
首先,我禁用表的约束,然后使用SQLLoader加载批量数据,最后启用禁用的约束,我得到ORA-08103错误。
答案 0 :(得分:3)
当我们尝试对不存在的对象运行DDL语句时,会发生ORA-08103。啊,但你说
他们总是在那里。他们永远不会被放弃
数据库对象(如表)在数据字典中有两个标识符:OBJECT_ID和DATA_OBJECT_ID:我们可以在the ALL_OBJECTS view中看到这些标识符。 OBJECT_ID在表的生存期内是常量,但DATA_OBJECT_ID - “包含对象的段的字典对象编号” - 随时间对对象执行DDL时更改。例如,当表被截断或重建索引时。
因此,根据您的情况:ORA-08103错误表示自运行游标后DATA_OBJECT_ID已更改。就在您运行程序时,其他人对其中一个表,约束或基础索引执行了DDL。
这可能是一个不幸的巧合,下次你运行程序时也不会发生这种情况。但是,您可以通过更改运行查询的方式来最小化另一次出现的可能性:
declare
tabs dbms_debug_vc2coll := dbms_debug_vc2coll ('TABLE_01', 'TABLE_02', 'TABLE_03', 'TABLE_04');
BEGIN
for idx in 1..tabs.count() loop
FOR c IN (
SELECT
c.owner,
c.table_name,
c.constraint_name
FROM user_constraints c
WHERE c.table_name = tabs(idx)
AND c.status = 'DISABLED'
) LOOP
EXECUTE IMMEDIATE 'ALTER TABLE ' || c.table_name || ' ENABLE CONSTRAINT ' || c.constraint_name;
END LOOP;
END LOOP;
END;
启用约束需要时间(因为需要验证它们)。因此,逐个选择表会减少您需要DATA_OBJECT_ID保持修复的时间。
“您的程序如何最大限度地减少出现同样错误的可能性?”
您的光标选择所有四个表,因此选择所有四个DATA_OBJECT_ID。假设在TABLE_01上启用约束时,另一个会话会修改TABLE_04。当您的过程转到TABLE_04时,DATA_OBJECT_ID已更改,您将获得ORA-08103。
但是如果您运行我的代码版本并不重要,因为在您准备好处理之前,您不会为TABLE_04选择DATA_OBJECT_ID。所以你会得到改变后的DATA_OBJECT_ID(不知道它被改变了。