Sql Oracle ROWNUM性能

Sql Oracle ROWNUM性能,sql,performance,oracle,Sql,Performance,Oracle,要在Oracle中查询top-n行,通常使用ROWNUM。 因此,以下查询似乎可以(获取最近的5笔付款): 第二点: SELECT STATEMENT, GOAL = ALL_ROWS 86 5 175 COUNT STOPKEY VIEW 86 81 2835 COUNT VIEW 86 81 1782 SORT ORDER BY 86 81 1620 TABLE ACCESS BY INDEX ROWID 85

要在Oracle中查询top-n行,通常使用ROWNUM。 因此,以下查询似乎可以(获取最近的5笔付款):

第二点:

SELECT STATEMENT, GOAL = ALL_ROWS   86  5   175
COUNT STOPKEY           
VIEW    86  81  2835
COUNT           
VIEW    86  81  1782
SORT ORDER BY   86  81  1620
TABLE ACCESS BY INDEX ROWID 85  81  1620
INDEX RANGE SCAN    4   81  
显然,正是索引全扫描下降使得大型表的第一次查询效率低下。但我无法通过查看两个查询来真正区分它们的逻辑。 有人能给我解释一下人类语言中两个查询之间的逻辑差异吗


提前谢谢

首先,正如Alex评论中提到的,我不确定您的第二个版本是否100%保证为您提供正确的行—因为查询的“中间”块没有明确的
order by
,Oracle没有义务以任何特定顺序将行传递给外部查询块。但是,似乎没有任何特殊原因会改变行从最里面的块向上传递的顺序,因此在实践中它可能会起作用

这就是为什么Oracle为第二个查询选择了不同的计划——从逻辑上讲,它无法将
STOPKEY
操作应用于最内部的查询块

我认为在第一种情况下,优化器假设
id
值分布良好,对于任何给定的值,都可能有一些最近的事务。由于它可以看到它只需要查找最近的5个匹配项,因此它计算出,使用索引以
paydate
的降序扫描行,从表中查找相应的id和其他数据,并在找到前5个匹配项时停止,似乎更为有效。我猜想,根据您使用的特定id值,您可能会看到此查询的性能有很大不同——如果id有很多最近的活动,那么应该很快找到行,但是如果没有,索引扫描可能需要做更多的工作

在第二种情况下,我认为由于额外的嵌套层,它无法将
STOPKEY
优化应用于最内层的块。在这种情况下,索引完整扫描将变得不那么吸引人,因为它总是需要扫描整个索引。因此,它选择在
id
(我假设)上进行索引查找,然后在日期上进行实际排序。如果给定的
id
值与一小部分行匹配,这可能会更有效——但如果给定的
id
在整个表中分布了大量行,我希望它会变慢,因为它必须访问和排序许多行


因此,我猜您的测试使用了
id
值,这些值的行数相对较少,并且不是最近的。如果这是一个典型的用例,那么第二个查询可能更适合您(同样,我不确定它在技术上是否能保证生成正确的结果集)。但是,如果典型值更可能有许多匹配行和/或更可能有5个最近的行,那么第一个查询和计划可能更好。

id是绑定变量,no(应该是:id?)如果是,使用什么值(相同?)我不认为第二个版本中用于过滤器的
rownum
保证与第一个版本相同;您认为您需要为第二个查询别名并引用它,或者在针对
a
的查询中添加
orderbyrownum
?我怀疑这会影响速度。很好的解释!谢谢@亚历克斯:似乎最好添加按行数排序的
order
,因为它在exec计划中添加了“按STOPRKEY排序顺序”,而别名
rownum
则删除了exec计划中的“COUNT STOPKEY”。但是,正如你所指出的,我还没有看到速度的变化。
select *
from (
  select  a.*, rownum
  from (select t.paydate, t.amount
        from payments t
        where t.some_id = id
        order by t.paydate desc) a
)
where rownum <= 5;
SELECT STATEMENT, GOAL = ALL_ROWS   7   5   175
COUNT STOPKEY           
VIEW    7   5   175
TABLE ACCESS BY INDEX ROWID 7   316576866   6331537320
INDEX FULL SCAN DESCENDING  4   6   
SELECT STATEMENT, GOAL = ALL_ROWS   86  5   175
COUNT STOPKEY           
VIEW    86  81  2835
COUNT           
VIEW    86  81  1782
SORT ORDER BY   86  81  1620
TABLE ACCESS BY INDEX ROWID 85  81  1620
INDEX RANGE SCAN    4   81