根据我的理解,rownum在查询后应用于整个结果集。这意味着如果我想使用rownum限制结果,它仍然会首先查询所有内容。我有一个超过十万条记录的用户表。我也正在开发一个搜索此表的站点,返回结果集。不幸的是,请求者希望我包含搜索JUST姓氏的能力。
想象一下可能会回来的“琼斯”,“白人”,“棕色”。我想带回不超过200条记录,有没有更好的方法来做这个而不是使用rownum?我对rownum应用时的理解是正确的吗?
答案 0 :(得分:8)
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在查询后应用于整个结果集
没有。只要获取满足rownum
子句的每条记录(但在订购它们之前),就会应用WHERE
。
实际上,此处需要嵌套查询,因为在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)
。