15

私の前の質問からのフォローアップ:

PostgreSQL でのページングに「カーソル」を使用する

API クライアントに 1,000,000 件のデータベース結果を提供する良い方法は何ですか?

現在、PostgreSQL を使用しています。いくつかの推奨される方法:

  • カーソルを使用したページング
  • 乱数を使用したページング (各クエリに "GREATER THAN ORDER BY" を追加)
  • LIMIT と OFFSET を使用したページング (非常に大きなデータ セットでは機能しません)
  • 情報をファイルに保存し、クライアントにダウンロードさせる
  • 結果を反復処理し、データをクライアント サーバーに POST します。
  • キーのみをクライアントに返し、クライアントが Amazon S3 などのクラウド ファイルからオブジェクトを要求できるようにします (ファイル名を取得するためだけにページングが必要な場合もあります)。

馬鹿げたほどシンプルで、これらのオプションのどれよりも優れているとは思いませんでしたか?

4

2 に答える 2

32

テーブルには主キーがあります。それを利用してください。

との代わりにLIMITOFFSET主キーのフィルターを使用してページングを行います。あなたはコメントでこれをほのめかしました:

乱数を使用したページング (各クエリに "GREATER THAN ORDER BY" を追加)

しかし、それをどのように行うべきかについてランダムなことは何もありません。

SELECT * FROM big_table WHERE id > $1 ORDER BY id ASC LIMIT $2

クライアントが、最後に確認した ID と取得するレコード数の両方のパラメーターを指定できるようにします。API には、プレースホルダー、追加のパラメーター、または「最初のn 個の ID を取得する」ための代替呼び出しのいずれかが必要になりますが、それWHEREはクエリから句を省略しますが、それは些細なことです。

このアプローチでは、かなり効率的なインデックス スキャンを使用してレコードを順番に取得し、通常、並べ替えや、スキップされたすべてのレコードを反復処理する必要を回避します。クライアントは、一度に必要な行数を決定できます。

このアプローチは、1 つの重要な点でLIMITandOFFSETアプローチとは異なります。それは、同時変更です。一部のクライアントがすでに見たキーよりも低いINSERTキーでテーブルに入ると、このアプローチは結果をまったく変更しませんが、アプローチは行を繰り返します。同様に、既に表示されている ID よりも小さい行の場合、このアプローチの結果は変わりませんが、表示されていない行はスキップされます。ただし、生成されたキーを持つ追加専用テーブルには違いはありません。OFFSETDELETEOFFSET

クライアントが結果セット全体を必要とすることが事前にわかっている場合、最も効率的な方法は、このページング ビジネスを使用せずに結果セット全体をクライアントに送信することです。そこでカーソルを使います。DB から行を読み取り、クライアントが受け入れるのと同じ速さでクライアントに送信します。この API は、過剰なバックエンドの負荷を回避するために、クライアントの許容速度に制限を設定する必要があります。遅いクライアントの場合、おそらくページングに切り替えるか(上記のように)、カーソル全体の結果を一時ファイルにスプールしてDB接続を閉じます。

重要な注意事項:

  • UNIQUE制約/UNIQUEインデックスまたはPRIMARY KEY信頼性が必要
  • limit/offset に対するさまざまな同時変更動作については、上記を参照してください。
于 2012-10-30T23:57:18.523 に答える
1

開始するオフセットと返されるレコードの数を API が受け入れるようにします。これは、クライアントが 1 つのページ要求で返すレコードの数を決定できる一種のページングです。また、API は、クライアントが「ページ」の数を知ることができるように、クエリで可能なレコードの総数を返す必要があります。または、返されたレコードの数がゼロまたは要求されたレコード。これは、SELECT ステートメントで OFFSET 句 (取得を開始するレコード) と LIMIT 句 (返されるレコードの数) を使用して、PostgresSQL クエリで制御できます。

于 2012-10-30T17:12:53.490 に答える