【发布时间】:2012-02-26 00:44:40
【问题描述】:
要在Oracle 中查询top-n 行,一般使用ROWNUM。 所以下面的查询似乎没问题(获得最近的 5 笔付款):
select a.paydate, a.amount
from (
select t.paydate, t.amount
from payments t
where t.some_id = id
order by t.paydate desc
) a
where rownum <= 5;
但是对于非常大的桌子,它的效率很低 - 对我来说它运行大约 10 分钟。 所以我尝试了其他查询,我最终得到了这个运行不到一秒钟的查询:
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
显然,正是 INDEX FULL SCAN DESCENDING 使得大表的第一次查询效率低下。但是我无法通过查看它们来真正区分两个查询的逻辑。 谁能解释一下人类语言中两个查询之间的逻辑差异?
提前致谢!
【问题讨论】:
-
id 是绑定变量,否(应该是 :id ?)如果是,使用什么值(相同?)
-
我认为您在第二个版本中用于过滤器的
rownum不能保证与第一个版本中的相同;认为您需要为第二个查询设置别名并引用它,或者在针对a的查询中添加order by rownum?我怀疑这会影响速度。
标签: sql performance oracle