Oracle DDL在自治事务中

swa*_*ord 7 oracle ddl transactions constraints ora-00054

我需要在Oracle数据库上执行一堆(最多~1000000)sql语句.这些语句应该在结尾处产生引用一致的状态,并且如果发生错误,应该回滚所有语句.这些陈述不是以参考顺序出现的.因此,如果启用了外键约束,则其中一个语句可能会导致外键违规,即使这种违规也将通过稍后将执行的语句修复.

我尝试首先禁用外键并在执行所有语句后启用它们.我认为当有实际的外键违规时我能够回滚.我错了,我发现Oracle中的每个DDL语句都以提交开始,因此无法以这种方式回滚语句.这是我的禁用外键的脚本:

begin 
  for i in (select constraint_name, table_name from user_constraints
            where constraint_type ='R' and status = 'ENABLED') 
    LOOP execute immediate 'alter table '||i.table_name||' disable constraint 
                           '||i.constraint_name||''; 
  end loop;
end;
Run Code Online (Sandbox Code Playgroud)

经过一些研究,我发现建议在自治事务中执行DDL语句,就像在这种情况下一样.所以我试图在自治事务中运行DDL语句.这导致以下错误:

ORA-00054:资源繁忙并且使用NOWAIT指定获取

我猜这是因为主事务仍然对表有DDL锁定.

我在这里做错了什么,还是有其他办法让这个场景有效?

Gar*_*ers 8

有几种可能的方法.

首先要考虑的是,无论你在表级别做什么,都将适用于使用该表的所有会话.如果您没有对该表的独占访问权限,则可能不希望删除/重新创建约束,或禁用/启用它们.

要考虑的第二件事是你可能不希望能够回滚一百万次插入/更新.回滚可以缓慢.

通常我会加载到临时表中.然后从临时表中执行单个INSERT到目标表.作为单个语句,Oracle将在最后应用所有检查约束.

如果您无法通过临时表(例如更新现有数据),那么在开始之前,可以将约束最终立即推迟.然后,在你的会话中,

SET CONSTRAINTS emp_job_nn, emp_salary_min DEFERRED;
Run Code Online (Sandbox Code Playgroud)

然后,您可以应用更改,并在提交时验证约束.

您应该使用DML错误日志记录,因为它可以帮助识别导致违规的任何行.