3

私の理解では、rownumは、クエリが実行された後、結果セット全体に適用されます。つまり、rownumを使用して結果を制限したい場合でも、最初はすべてをクエリします。10万を超えるレコードを持つユーザーテーブルがあります。また、このテーブルを検索して結果セットを返すサイトを開発しています。残念ながら、リクエスターは私に姓だけを検索する機能を含めることを望んでいます。

戻ってくる可能性のある「ジョーンズ」、「ホワイト」、「ブラウンズ」について想像してみてください。200レコード以下を戻したいのですが、rownumを使用する代わりにこれを行うためのより良い方法はありますか?rownumがいつ適用されるかについての私の理解は正しいですか?

4

1 に答える 1

9
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)ます。

于 2012-05-23T19:29:44.997 に答える