Oracle rownum< [n]替代方案?对此事的认知?

时间:2012-05-23 19:25:49

标签: sql oracle

根据我的理解,rownum在查询后应用于整个结果集。这意味着如果我想使用rownum限制结果,它仍然会首先查询所有内容。我有一个超过十万条记录的用户表。我也正在开发一个搜索此表的站点,返回结果集。不幸的是,请求者希望我包含搜索JUST姓氏的能力。

想象一下可能会回来的“琼斯”,“白人”,“棕色”。我想带回不超过200条记录,有没有更好的方法来做这个而不是使用rownum?我对rownum应用时的理解是正确的吗?

1 个答案:

答案 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

ROWNUMROW_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)