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

Posted

技术标签:

【中文标题】优化删除... where 使用 rownum 查询【英文标题】:Optimizing a delete... where query with rownum 【发布时间】:2015-01-19 13:02:43 【问题描述】:

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

delete outdatedTable where referenceDate < :deletionCutoffDate

如果要运行此语句,则需要很长时间才能完成,因此我宁愿将其分解为以下内容:

delete outdatedTable where referenceData < :deletionCutoffDate and rownum <= 10000

在测试中,这运行起来非常缓慢。但是,以下查询的运行速度要快得多:

delete outdatedTable where rownum <= 10000

我一直在阅读有关 *** 的多个博客和类似问题,但我还没有找到关于在查询中有其他 Where 子句时使用 rownum 如何/是否影响 Oracle 优化器的直接描述。就我而言,在我看来好像 Oracle 会检查

referenceData < :deletionCutoffDate

在每一行上,对所有匹配的行执行大量选择,然后过滤掉前 10000 行返回。事实是这样吗?如果是这样,有没有什么聪明的方法可以让 Oracle 在找到足够的匹配行后立即停止检查 Where 子句?

【问题讨论】:

也许可以尝试在DBA 网站上询问 - “高级查询,包括窗口函数、动态 SQL、 和查询性能 是在那里明确列为主题。 我建议您保留要保留的备份条目(到另一个新表中),然后删除表并将备份表重命名为原始名称。 deletionCutoffDate 上有索引吗? 是的,日期有索引。 【参考方案1】:

如果没有太多的DML,如何采用不同的方法。作为未来的永久解决方案,您可以选择表分区

    创建一个包含所需分区的新表。 仅将所需行从现有表移动到新的分区表。 填充新表后,添加所需的约束和索引。 放下旧桌子。

以后,您只需DROP 旧分区

CTAS(create table as select)是另一种方式,但是,如果您想拥有一个带分区的新表,则必须采用交换分区概念。

【讨论】:

【参考方案2】:

首先,你应该read about SQL statement's execution plan and learn how to explain in。它将帮助您找到此类问题的答案。

一般来说,一次删除比多次分块更有效。它的主要缺点是极端使用撤消表空间。

如果你想删除表格的大部分行,更快的方法通常是一个技巧:

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 ...

如果您希望多次执行此操作,分区是一种更好的方法。如果按日期对表进行分区,则可以快速选择实际日期,并且可以以毫秒为单位删除带有过期数据的分区。

最后,分区是一种完全消除“删除过时记录”的方法。有时我们需要旧数据,如果我们亲手删除它是很可悲的。通过分区,您可以在数据库之外归档过时的分区,但在需要访问旧数据时连接它们。

【讨论】:

【参考方案3】:

这是一个旧请求,但我想展示另一种方法(也使用分区)。

根据您认为旧的,您可以创建相应的分区(最好是两个;一个当前的,一个旧的;但您也可以制作更多),例如:

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;

【讨论】:

【参考方案4】:

delete from your_table where PK not in (select PK from your_table where rounum<=...) -- 这些记录你要留下

【讨论】:

以上是关于优化删除... where 使用 rownum 查询的主要内容,如果未能解决你的问题,请参考以下文章

ROWNUM使用大于查不到值的问题(查询大于10小于21 范围内的数据)

删除 where 子句然后添加回来时的执行计划优化

Oracle/SQL:为啥查询“SELECT * FROM records WHERE rownum >= 5 AND rownum <= 10” - 返回零行

rownum

我可以使用 `rownum` 来优化 apache spark 读取 oracle 表吗? [复制]

rownum 的使用