我正在处理一个应用程序,该应用程序中有大量过时的数据堵塞了我的数据库中的表格。理想情况下,我希望删除表格中参考日期过旧的所有条目:
delete outdatedTable where referenceDate < :deletionCutoffDate
如果要执行此声明,则需要很长时间才能完成,所以我宁愿将其分解为以下块:
delete outdatedTable where referenceData < :deletionCutoffDate and rownum <= 10000
在测试中,这种工作效果令人惊讶。但是,以下查询的运行速度要快得多:
delete outdatedTable where rownum <= 10000
我一直在阅读StackOverflow上的多个博客和类似问题,但我还没有找到一个简单的描述,当查询中有其他Where子句时,如何/是否使用rownum会影响Oracle优化器。就我而言,在我看来好像Oracle检查
referenceData < :deletionCutoffDate
在每一行上,对所有匹配的行执行大量选择,然后过滤掉前10000行以返回。事实上是这样的吗?如果是这样,有没有聪明的方法让Oracle在找到足够匹配的行后立即停止检查Where子句?
答案 0 :(得分:1)
在桌面上没有那么多 DML 的不同方法怎么样?作为未来的永久解决方案,您可以选择表格分区。
将来,您只需要 DROP 旧分区。
CTAS (创建表格为select)是另一种方式,但是,如果你想要一个带分区的新表,你必须选择交换分区的概念。
答案 1 :(得分:1)
首先,你应该read about SQL statement's execution plan and learn how to explain in。它将帮助您找到有关此类问题的答案。
通常,一次删除比几次删除更有效。它的主要缺点是使用undo表空间。
如果你想删除大多数表格的行,那么通常的方法要快得多:
create table new_table as select * from old_table where date >= :date_limit;
drop table old_table;
rename table new_table to old_table;
... recreate indexes and other stuff ...
如果您希望不止一次这样做,分区是一种更好的方法。如果按日期分区表,您可以快速选择实际日期,并且可以在几毫秒内删除过时数据。
最后,如果有办法解雇和删除过时的记录,则会进行分区。一点都不有时候我们需要旧数据,如果我们自己删除数据会很难过。通过分区,您可以存档数据库外部的过时分区,但在需要访问旧数据时将它们连接起来。
答案 2 :(得分:0)
这是一个旧请求,但我想展示另一种方法(也使用分区)。
根据您认为旧的内容,您可以创建相应的分区(最好恰好两个;一个当前,一个旧;但您也可以创建更多),例如:
PARTITION BY LIST ( mod(referenceDate,2) )
(
PARTITION year_odd VALUES (1),
PARTITION year_even VALUES (0)
);
这可能是几个月(1月,2月,12月),数十年(XX0X,XX1X,...... XX9X),半年(first_half,second_half)等等。任何循环。
然后,每当你想要删除旧数据时,截断:
ALTER TABLE mytable TRUNCATE PARTITION year_even;
答案 3 :(得分:0)
delete from your_table
where PK not in
(select PK from your_table where rounum<=...)
- 您想要离开的这些记录