web-dev-qa-db-ja.com

Oracleでのページング

私は自分が望むほどOracleに精通していません。約25万件のレコードがあり、それらを1ページに100個表示したい。現在、データアダプター、データセット、およびストアドプロシージャの結果に対するdataadapter.Fill(dataset)メソッドを使用して、25万件すべてのレコードをデータセットに取得するストアドプロシージャが1つあります。パラメータとして渡すことができる整数値として「ページ番号」と「ページあたりのレコード数」がある場合、その特定のセクションだけを取得する最良の方法は何でしょうか。たとえば、selectステートメントからページ番号として10、ページ番号として120を渡すと、1880番目から1200番目まで、またはそのようなものが得られます。私の頭の中で計算がオフになる可能性があります。

私は.NETでC#を使用してこれを行っていますが、これは重要ではないと考えました。SQL側で正しく実行できれば、クールになります。

更新:ブライアンの提案を使用することができました。最適化に取り組みたいのですが、ページは1分ではなく4〜5秒で表示され、ページングコントロールは新しいストアドプロシージャと非常にうまく統合できました。

86
stephenbayer

このような何かが動作するはずです: Frans Boumaのブログから

SELECT * FROM
(
    SELECT a.*, rownum r__
    FROM
    (
        SELECT * FROM ORDERS WHERE CustomerID LIKE 'A%'
        ORDER BY OrderDate DESC, ShippingDate DESC
    ) a
    WHERE rownum < ((pageNumber * pageSize) + 1 )
)
WHERE r__ >= (((pageNumber-1) * pageSize) + 1)
129
Brian Schmitt

トムに質問 ページネーションと非常に便利な分析関数について。

これはそのページからの抜粋です:

select * from (
    select /*+ first_rows(25) */
     object_id,object_name,
     row_number() over
    (order by object_id) rn
        from all_objects)
    where rn between :n and :m
        order by rn;
125
Chobicus

完全を期すために、より現代的なソリューションを探している人々のために、Oracle 12cには、ページングやトップハンドリングの改善を含むいくつかの新機能があります。

ページング

ページングは​​次のようになります。

SELECT *
FROM user
ORDER BY first_name
OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY;

上位Nレコード

上位のレコードの取得は次のようになります。

SELECT *
FROM user
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY

上記のクエリ例の両方にORDER BY句があることに注意してください。新しいコマンドはこれらを尊重し、ソートされたデータに対して実行されます。

FETCHまたはOFFSETの適切なOracleリファレンスページは見つかりませんでしたが、 このページ にはこれらの新機能の概要が記載されています。

パフォーマンス

@wweickerが以下のコメントで指摘しているように、パフォーマンスは12cの新しい構文の問題です。 Oracleがそれを改善しているかどうかをテストする18cのコピーがありませんでした。

興味深いことに、新しいメソッドのテーブル(1億1300万行以上)で初めてクエリを実行したときに、実際の結果が少し速く返されました。

  • 新しい方法:0.013秒。
  • 古い方法:0.107秒。

ただし、@ wweickerが述べたように、新しいメソッドの説明計画ははるかに悪く見えます。

  • 新しいメソッドのコスト:300,110
  • 古い方法のコスト:30

新しい構文により、列のインデックスのフルスキャンが発生しました。これは全体のコストでした。インデックス化されていないデータを制限すると、事態はさらに悪化します。

前のデータセットにインデックスのない単一の列を含める場合を見てみましょう。

  • 新しいメソッドの時間/コスト:189.55秒/ 998,908
  • 古いメソッドの時間/コスト:1.973秒/ 256

要約:Oracleがこの処理を改善するまで、注意して使用してください。使用するインデックスがある場合は、おそらく新しいメソッドを使用して回避できます。

うまくいけば、すぐにプレイできる18cのコピーがあり、更新できます。

59
JoelC

答えとコメントをまとめたいだけです。ページネーションを行う方法はいくつかあります。

Oracle 12cより前は、OFFSET/FETCH機能がなかったため、@ jasonkが示唆したように whitepaper を見てください。長所と短所の詳細な説明を含むさまざまな方法について私が見つけた最も完全な記事です。ここにコピーアンドペーストするにはかなりの時間がかかるため、私はそれを行いません。

また、jooq作成者による、Oracleおよびその他のデータベースのページネーションに関する一般的な注意事項を説明する優れた記事もあります。 jooqのブログ投稿

幸いなことに、Oracle 12cには新しいOFFSET/FETCH機能があります。 OracleMagazine 12cの新機能 。 「上位Nクエリとページネーション」を参照してください。

次の文を発行して、Oracleのバージョンを確認できます。

SELECT * FROM V$VERSION
10
Vadim Kirilchuk

以下を試してください:

SELECT *
FROM
  (SELECT FIELDA,
    FIELDB,
    FIELDC,
    ROW_NUMBER() OVER (ORDER BY FIELDC) R
  FROM TABLE_NAME
  WHERE FIELDA = 10
  )
WHERE R >= 10
AND R   <= 15;

[tecnicume] 経由

7
Furetto