优化删除... 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 范围内的数据)
Oracle/SQL:为啥查询“SELECT * FROM records WHERE rownum >= 5 AND rownum <= 10” - 返回零行