使用PL / SQL删除大量记录

时间:2015-03-17 15:53:19

标签: plsql oracle11g

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

我正在寻找有关这方面的最佳做法的建议。我也对我得到的警告感到担忧:

“包含DML语句的循环应该重构为使用BULK COLLECT和FORALL。”

但是当我谷歌这个主题时,似乎这不适用于我想要做的事情 - 或者它是什么?

欢迎您提出意见和建议。

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;

由于

1 个答案:

答案 0 :(得分:3)

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

实际上,退一步,最有效的方法是通过UPDT_TIMESTMP对表进行分区并删除旧分区。但是,除了企业版许可证之外,分区是一个额外的成本选项,对表格进行分区可能会对系统产生其他影响。

如果你确实需要使用临时提交批量删除行,这似乎是一个非常合理的实现。如果单DELETE语句占用了我夜间处理窗口的很大一部分,我真的只会考虑这个问题而且我担心DELETE可能会在几个小时后强制回滚并重新启动整个处理。批量删除比正常执行单DELETE要慢,但重启会更容易。

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