我想使用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;
由于
答案 0 :(得分:3)
您关注哪些资源消费?单个DELETE
语句将是最有效的方法*。假设这是需要定期完成的事情,那么数据库的确应根据UNDO
表空间进行适当调整,以允许您执行单个DELETE
。
实际上,退一步,最有效的方法是通过UPDT_TIMESTMP
对表进行分区并删除旧分区。但是,除了企业版许可证之外,分区是一个额外的成本选项,对表格进行分区可能会对系统产生其他影响。
如果你确实需要使用临时提交批量删除行,这似乎是一个非常合理的实现。如果单DELETE
语句占用了我夜间处理窗口的很大一部分,我真的只会考虑这个问题而且我担心DELETE
可能会在几个小时后强制回滚并重新启动整个处理。批量删除比正常执行单DELETE
要慢,但重启会更容易。
在这种特殊情况下,使用BULK COLLECT
和FORALL
的建议没有意义。它适用于更常见的情况,即某人从一个或多个源表中选择数据,在PL / SQL中执行某些处理,然后将数据写入目标表。通过批量操作而不是通过慢速逐行处理来实现这一点会更有效。但是,将它作为单个INSERT ... SELECT
进行更有效。