sql - 无需并行提示和批量收集即可删除数百万条记录

标签 sql database oracle plsql

我有一个表 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/

相关文章:

SELECT MIN(DATE) 的 SQL 语法

SQL 查询只返回一个列值的第一次出现

python - 将 django 项目迁移到新服务器,并且另一个 django 项目的 postgresql 数据库已存在

php - 通过 JOIN 在单个查询中查询多个表

sql - 具有递归层次结构的互连数据

oracle - 在一台 Windows 机器上运行两个 Docker Oracle 容器

php - 从数据库中提取数据并放入 html 表中

mysql - 根据一个表列更新另一表列

mysql - 从表中删除重复的行(每天的第一个时间戳除外)

java - Oracle:加载java类时如何避免 "java session state cleared"错误?