我需要从Oracle表中删除大约5百万条记录。 由于性能(REDO日志),我想删除每笔交易100000条记录,如下所示:
DECLARE
v_limit PLS_INTEGER :=100000;
CURSOR person_deleted_cur
IS
SELECT rowid
FROM Persons p
WHERE City = 'ABC'
AND NOT EXISTS
(SELECT O_Id
FROM Orders o
WHERE p.P_Id = o.P_Id);
TYPE person_deleted_nt IS TABLE OF person_deleted_cur%ROWTYPE
INDEX BY PLS_INTEGER;
BEGIN
OPEN person_deleted_cur;
LOOP
FETCH person_deleted_cur
BULK COLLECT INTO person_deleted_nt LIMIT v_limit;
FORALL indx IN 1 .. person_deleted_nt.COUNT
DELETE FROM Persons WHERE rowid=person_deleted_nt(indx);
EXIT WHEN person_deleted_cur%NOTFOUND;
END LOOP;
CLOSE person_deleted_cur;
COMMIT;
END;
但Liquibase在一个事务中运行changeSet,如果有任何错误则将其回滚。在Liquibase脚本中明显使用 COMMIT 是一个好习惯吗? 什么应该写得很好?
答案 0 :(得分:0)
在书中" Oracle专业人士" Tom Kyte写了关于其他交易的更新。关键是:如果您可以使用一个查询更改表,那么这样做。因为一个查询将比不同的事务更快或plsql循环与分区删除。
另一种方法是将CREATE TABLE
与NOLOGGING
一起使用,而不是UPDATE/DELETE
。这是更改多行的最佳解决方案。
所以用你的查询创建nologging表,而不是删除原始表并重新创建索引,约束等,而不是将temp table重命名为原始表。
答案 1 :(得分:0)
同意@jimmbraddock,但是对于OLTP系统来说影响较小的更简单的解决方案可能是重复运行此查询,直到它不再影响行:
DELETE FROM Persons p
WHERE City = 'ABC'
AND NOT EXISTS
(SELECT O_Id
FROM Orders o
WHERE p.P_Id = o.P_Id)
AND ROWNUM <= 100000;
总资源使用率将高于单个删除,因此如果您的系统可以容纳单个删除仍然会更好,但这将非常强大,并且具有人员索引(city,p_id)和一个订单(p_id)它应该是非常高效的。