11

次のような SQL クエリがあります。

SELECT * FROM(
    SELECT
        ...,
        row_number() OVER(ORDER BY ID) rn
    FROM
        ...
) WHERE rn between :start and :end

基本的に、速度を低下させているのは ORDER BY 部分です。これを削除すると、EXPLAIN のコストが 1 桁 (1000 倍以上) 下がります。私はこれを試しました:

SELECT 
    ...
FROM
    ...
WHERE
    rownum between :start and :end

しかし、これでは正しい結果が得られません。これを高速化する簡単な方法はありますか?それとも、EXPLAIN ツールにもう少し時間を費やす必要がありますか?

4

5 に答える 5

13

ROW_NUMBERで非常に非効率的ですOracle

パフォーマンスの詳細については、私のブログの記事を参照してください。

特定のクエリについては、次のように置き換えてROWNUM、インデックスが使用されていることを確認することをお勧めします。

SELECT  *
FROM    (
        SELECT  /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
                t.*, ROWNUM AS rn
        FROM    table t
        ORDER BY
                column
        )
WHERE rn >= :start
      AND rownum <= :end - :start + 1

このクエリはCOUNT STOPKEY

また、columnnull許容でないことを確認するか、WHERE column IS NOT NULL条件を追加してください。

そうしないと、インデックスを使用してすべての値を取得できません。

ROWNUM BETWEEN :start and :endサブクエリなしでは使用できないことに注意してください。

ROWNUMは常に最後に割り当てられ、最後にチェックされます。これROWNUMにより、常にギャップなしで順番に実行されます。

を使用するROWNUM BETWEEN 10 and 20と、他のすべての条件を満たす最初の行が戻る候補になり、一時的に割り当てられROWNUM = 1、のテストに失敗しROWNUM BETWEEN 10 AND 20ます。

次に、次の行が候補になり、割り当てられてROWNUM = 1失敗するなどのようになります。したがって、最終的に、行はまったく返されません。

これはROWNUM、サブクエリに'sを入れることで回避する必要があります。

于 2009-05-06T14:53:14.197 に答える
5

私にはページネーションクエリのように見えます。

この ASKTOM 記事から (ページの約 90% ダウン):

ROW_NUMBER が毎回決定論的に行に割り当てられるように、これらのページネーション クエリに固有のもので並べ替える必要があります。

また、あなたのクエリはどこも同じではないので、一方のコストを他方のコストと比較する利点が何であるかわかりません。

于 2009-05-05T23:12:05.007 に答える
1

ORDER BY 列はインデックス化されていますか? そうでない場合は、開始するのに適した場所です。

于 2009-05-05T22:04:30.910 に答える
0

EXPLAIN PLAN ツールにより多くの時間を費やします。TABLE SCAN が表示された場合は、クエリを変更する必要があります。

あなたの質問は私にはほとんど意味がありません。ROWID に対するクエリは、トラブルを求めているように思えます。そのクエリには関係情報がありません。問題を抱えているのは実際のクエリですか、それとも問題を説明するために作成した例ですか?

于 2009-05-05T22:53:07.440 に答える