优化删除...使用rownum查询

时间:2015-01-19 13:02:43

标签: oracle query-optimization sql-delete rownum

我正在处理一个应用程序,该应用程序中有大量过时的数据堵塞了我的数据库中的表格。理想情况下,我希望删除表格中参考日期过旧的所有条目:

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子句?

4 个答案:

答案 0 :(得分:1)

在桌面上没有那么多 DML 的不同方法怎么样?作为未来的永久解决方案,您可以选择表格分区

  1. 创建一个包含所需分区的新表。
  2. 仅将现有表格中所需的行移至新的分区表格。
  3. 填充新表后,添加所需的约束和索引。
  4. 放下旧桌子。
  5. 将来,您只需要 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<=...) - 您想要离开的这些记录