批量更新执行流程如何工作

时间:2013-09-05 20:38:15

标签: stored-procedures oracle11g forall bulk-collect

我正在编写一些代码,这些代码将数十亿的数据从一个表复制到另一个表,我们不希望在异常的情况下停止该过程。所以我正在编写脚本(不是100%可编译的语法)

dml_errors      exception;
errors          number;
error_count     number;
pragma exception_init (dml_errors, -24381);

---------
open cursor;
begin loop;
   fetch cursor bulk collect into tbl_object limit batch_size;
   exit when tbl_object.count = 0;
   -- perform business logic
   begin
       forall in tbl_object save exceptions;
          insert into table;
          tbl_object.delete;
   exception
       when dml_errors then
                errors      :=  sql%bulk_exceptions.count;
                error_count :=  error_count + errors;
                insert into log_table (tstamp, line) values (sysdate, SUBSTR('[pr_procedure_name:'||r_guid||'] Batch # '||batch_number - 1||' had '||errors||' errors',1,300));
   end;
end loop;
close cursor;
end procedure;

现在根据这个pseduo代码我有两个问题

  1. 我在forall循环中删除了我的收藏。如果有异常并且我决定从dml_errors块中的我的集合中获取一些信息,那么我会在那里收集元素吗?如果是,那么在登录后删除它们是否安全?
  2. 由于我将我的forall保留在begin-exception-end块中,它会继续迭代吗?

1 个答案:

答案 0 :(得分:1)

您确定需要在这里使用PL / SQL吗?除非您在业务逻辑中进行了大量处理,而您没有向我们展示无法在SQL中完成的处理,否则我倾向于使用DML error logging。这将更有效,更少的代码,并为您提供更好的日志记录。

DBMS_ERRLOG.CREATE_ERROR_LOG( 'DESTINATION_TABLE' );

INSERT INTO destingation_table( <<columns>> )
  SELECT <<columns>>
    FROM source_table
  LOG ERRORS 
  REJECT LIMIT UNLIMITED;

我认为没有理由从您的tbl_object集合中删除。这似乎并没有让你获得任何好处。这只是花费一些时间。如果您的缩进表示您预期的控制流程,那么您认为deleteforall循环的一部分 - 这是不正确的。只有insertforall的一部分,delete是一个单独的操作。

如果你的第二个问题是“如果在迭代N中引发异常,那么循环是否仍会进行第N + 1次获取”,答案是肯定的,它会。

有一点需要注意 - 由于error_count未初始化,因此它始终为NULL。您需要将其初始化为0,以便记录错误总数。