我有一个表 PROD_MAIN,它在单个数据库上有 7.5 亿条记录。数据库基础设施非常基础,上面没有任何 RAC。它只是 1 个数据库。 要求是删除1年以上的记录。我编写了带有并行提示和批量收集的 PL SQL 代码。执行起来需要很长时间。请找到下面的代码。
ALTER SESSION ENABLE PARALLEL DML;
DECLARE
TYPE TABLE_DELETE IS TABLE OF ROWID;
T_DELETE TABLE_DELETE;
CURSOR C_DELETE IS
SELECT /*+ PARALLEL(10) */ ROWID FROM PROD_MAIN WHERE RECORD_DATE < (TRUNC(SYSDATE) - 366);
L_DELETE_BUFFER PLS_INTEGER := 50000;
BEGIN
OPEN C_DELETE;
LOOP
FETCH C_DELETE BULK COLLECT
INTO T_DELETE LIMIT L_DELETE_BUFFER;
FORALL I IN 1..T_DELETE.COUNT
DELETE /*+ PARALLEL(10) */ PROD_MAIN WHERE ROWID = T_DELETE(I);
EXIT WHEN C_DELETE%NOTFOUND;
COMMIT;
END LOOP;
CLOSE C_DELETE;
COMMIT;
END;
ALTER SESSION DISABLE PARALLEL DML;
我还在 table 上做了NOLOGGING。我创建了索引并进行了统计收集,但性能没有提高。那么,有没有其他方法可以在3-5小时内删除数百万条记录呢?
最佳答案
如果表是按日期分区的,则可以截断一年以上的分区(截断分区不需要时间,不会降低表的性能)
如果它没有分区,我认为您能做的最好的事情就是不要尝试删除单个事务中的所有记录。尝试删除一些记录并将其放入循环中。例如,如果您想删除 10.000 条记录,您可以执行以下操作:
DELETE FROM your_table WHERE your_conditions LIMIT 10.000 (MySQL)
DELETE FROM your_table WHERE your_conditions AND rownum <10000 (Oracle)
请记住在完成后(甚至在删除之间交替)优化表,因为这会降低索引。
根据您的环境要求,您可以尝试的另一件事是创建一个空表副本,并从 SELECT 执行 INSERT,在新表中插入您想要维护的所有行。之后,截断原始表,删除它,然后重命名新表。
MyOriginalTable whit All Data
Create en Empty Copy: MyTemporalTable (without indexes)
Move valid data from MyOriginalTable to MyTemporalTable
Truncate and Drop MyOriginalTable
Create indexes in MyTemporalTable
Rename MyTemporalTable to MyORiginalTable
关于sql - 无需并行提示和批量收集即可删除数百万条记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38929719/