SELECT *
FROM (
SELECT *
FROM mytable
WHERE lastname = 'Jones'
ORDER BY
id
)
WHERE rownum <= 200
或者
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id) rn
FROM mytable
WHERE lastname = 'Jones'
)
WHERE rn <= 200
在9i
版本中后者速度较慢,但在10g+
版本中表现相同。
我的理解是,在查询完成后对整个结果集应用rownum。
不是这样的。当满足WHERE
子句的每条记录被获取(但在排序之前),rownum
就会被应用。
实际上,在此处需要嵌套查询,因为ROWNUM
在ORDER BY
之前被评估。
无论是ROWNUM
还是ROW_NUMBER()
, 都会受到优化。如果你在(lastname, id)
上建立了索引,查询将使用该索引,并在返回第200条记录后停止(可以在计划中看到COUNT(STOPKEY)
)。
此外,ROWNUM
和分页有一个常见的陷阱。 这个查询:
SELECT *
FROM (
SELECT *
FROM mytable
WHERE lastname = 'Jones'
ORDER BY
id
)
WHERE rownum BETWEEN 201 AND 400
这个查询语句将永远不会返回任何结果,因为 ROWNUM
已经是 WHERE
条件的一部分。数据库引擎无法返回第一行,因为它将具有 ROWNUM = 1
,而这不满足 WHERE
子句的条件。
要解决这个问题,你需要再加一层嵌套查询:
SELECT *
FROM (
SELECT q.*, ROWNUM AS rn
FROM (
SELECT *
FROM mytable
WHERE lastname = 'Jones'
ORDER BY
id
) q
)
WHERE rn BETWEEN 201 AND 400
这也将被优化为一个 COUNT(STOPKEY)
。