我有一个表PROD_MAIN,在一个数据库上有7.5亿条记录。数据库基础结构非常基础,并且没有任何RAC。它只是一个数据库。 要求是删除超过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;
我也在桌子上做了NOLOGGING。我创建了索引并进行了统计收集,但性能没有提高。那么,还有其他方法可以在3到5个小时内删除数百万条记录吗?
答案 0 :(得分:1)
如果表按日期分区,则可以截断超过一年的分区(截断分区不会立即降低表的性能)
如果没有分区,我认为你能做的最好的办法就是不要尝试删除一个事务中的所有记录。尝试删除一些记录并将其放入循环中。例如,我想删除您可以执行的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
答案 1 :(得分:1)
我认为问题是:这个表是其他表的主表。
加快禁用其他表中的外键。然后删除行,然后启用索引。
但是'Diego Sal Diaz'的第三个解决方案是将剩余的行复制到临时表并重命名它也很好。
答案 2 :(得分:0)
我通过创建一个临时表PROD_MAIN_TEMP解决了这个问题,该表具有类似PROD_MAIN的确切表结构。创建后,我插入了我想要保留的数据。 SELECT / * + PARALLEL(10)* / * FROM PROD_MAIN WHERE RECORD_DATE&lt; (TRUNC(SYSDATE) - 366); 删除表主表PROD_MAIN并将临时表PROD_MAIN_TEM重命名为PROD_MAIN。 整个过程在3个小时内完成。