使用 PL/SQL 删除大量记录

Deleting a large number of records using PL/SQL

我想使用 PL/SQL 删除大量记录。记录由标识上次修改记录的日期字段标识。我不想消耗太多资源,所以我认为我应该限制被删除的记录数,在我看来伪列 ROWNUM 可以达到这个目的。然后我检查受更新影响的行数并重复直到受影响的行数为 0。

我正在寻找有关执行此操作的最佳实践的建议。我也很担心我收到的警告:

"A loop that contains DML statements should be refactored to use BULK COLLECT and FORALL."

但是当我 google 这个话题时,这似乎不适用于我正在尝试做的事情——或者我正在做吗?

欢迎您提出意见和建议。

CREATE OR REPLACE PACKAGE BODY MY_PURGE
AS
   PROCEDURE PURGE_MY_TABLE (v_Cut_Off_Date   IN     DATE,
                                 C_MAX_DELETE     IN NUMBER,
                                 DEL_COUNT        OUT NUMBER)
   IS
      v_RECORDS_DELETED   NUMBER := 0;
      V_DONE              BOOLEAN := FALSE;
   BEGIN
      DEL_COUNT := 0;

      WHILE NOT V_DONE
      LOOP
         DELETE FROM MYTABLE
               WHERE     UPDT_TIMESTMP < v_Cut_Off_Date
                     AND ROWNUM <= C_MAX_DELETE;

         v_RECORDS_DELETED := SQL%ROWCOUNT;
         DEL_COUNT := DEL_COUNT + v_RECORDS_DELETED;

         IF (v_RECORDS_DELETED = 0)
         THEN
            V_DONE := TRUE;
         END IF;

         COMMIT;
      END LOOP;
   END;

谢谢

您担心消耗哪些资源?单个 DELETE 语句将是最有效的方法*。假设这是需要定期完成的事情,那么数据库的大小确实应该根据 UNDO table 空间适当调整,以允许您执行单个 DELETE

实际上,退一步说,最有效的方法是用 UPDT_TIMESTMP 对 table 进行分区,然后删除较旧的分区。但是分区是企业版许可证之上的额外成本选项,并且分区 table 可能会对系统产生其他影响。

如果您真的非常需要通过临时提交批量删除行,这似乎是一个非常合理的实现。如果单个 DELETE 语句占用了我夜间处理的很大一部分 window 并且我担心 DELETE 可能会在几个小时后强制回滚和重新开始整个过程​​。批量删除会比正常删除单个 DELETE 慢,但重新启动会更容易。

使用 BULK COLLECTFORALL 的建议在这种特殊情况下没有意义。它适用于更常见的情况,即某人从一个或多个源 table 中选择数据,在 PL/SQL 中进行一些处理,然后将数据写出到目标 table。通过批量操作而不是通过缓慢的逐行处理来做到这一点会更有效。但是作为单个 INSERT ... SELECT.

来做会更有效率