8

ページネーションを使用して PostgreSQL から多くの行を取得する HTTP 経由の API を作成しています。通常、私は通常、naive OFFET/LIMIT句を介してこのようなページネーションを実装します。ただし、この場合、いくつかの特別な要件があります。

  • 多くの行があるため、ユーザーは最後に到達できないと思います (Twitter のタイムラインを想像してください)。
  • ページはランダムにアクセスできる必要はなく、順番にのみアクセスできます。
  • API は、連続したチャンクのページに移動するカーソル トークンを含む URL を返します。
  • カーソルトークンは永続的に存在する必要はありませんが、しばらくの間存在する必要があります。
  • その順序は (Reddit ランキングのように) 頻繁に変動しますが、連続カーソルは一貫した順序を維持する必要があります。

どうすればミッションを達成できますか? データベーススキーマ全体を変更する準備ができました!

4

2 に答える 2

6

変動するのは結果の順序のみであり、行のデータではないと仮定すると、Fredrikの答えは理にかなっています。ただし、次の追加をお勧めします。

  • IDリストは、メモリではなく配列型を使用してpostgresqlテーブルに格納します。自動有効期限とメモリ制限を備えたredisのようなものを注意深く使用しない限り、メモリ内でそれを行うことは、DOSメモリ消費攻撃に備えることです。私はそれがこのように見えるだろうと想像します:

    create table foo_paging_cursor (
      cursor_token ..., -- probably a uuid is best or timestamp (see below)
      result_ids integer[], -- or text[] if you have non-integer ids
      expiry_time TIMESTAMP
    );
    
  • 必要なストレージとユーザーごとの初期クエリの実行に必要な時間を削減するために、cursor_tokenとresult_idsをユーザー間で共有できるかどうかを決定する必要があります。それらを共有できる場合は、たとえば1分または5分などのキャッシュウィンドウを選択し、新しいリクエストでその期間のcache_tokenを作成し、そのトークンの結果IDがすでに計算されているかどうかを確認します。そうでない場合は、そのトークンの新しい行を追加します。新しいトークンの同時リクエストを処理するには、チェック/挿入コードの周りにロックを追加する必要があります。

  • 古いトークン/結果を削除するスケジュールされたバックグラウンドジョブを用意し、クライアントコードが期限切れ/無効なトークンに関連するエラーを処理できることを確認します。

これに実際のdbカーソルを使用することさえ考えないでください。

結果IDをRedisリストに保持することは、これを処理する別の方法です(LRANGEコマンドを参照)が、そのパスをたどる場合は、有効期限とメモリ使用量に注意してください。Redisキーはcursor_tokenになり、IDはリストのメンバーになります。

于 2011-10-19T21:44:59.007 に答える
1

私はPostgreSQLについてまったく何も知りませんが、私はかなりまともなSQL Server開発者なので、とにかくこれを試してみたいと思います:)

ユーザーがセッションごとに最大で何行/ページをブラウズすると予想しますか? たとえば、ユーザーがセッションごとに最大 10 ページ (各ページには 50 行を含む) をページングすることが予想される場合、その最大数を取得して、ユーザーが最初のページを要求したときにキャッシュするように Web サービスをセットアップできます。 10*50 行 (または、行の Id:s のみ、取得したメモリ/同時ユーザーの量によって異なります)。

これは確かに、複数の方法で Web サービスを高速化するのに役立ちます。そして、それを実装するのは非常に簡単です。そう:

  • ユーザーがページ #1 からデータを要求したとき。クエリを実行し (order by、join チェックなどで完了)、すべての id:s を配列に格納します (ただし、最大 500 個の ID)。配列の 0 ~ 9 の位置にある id:s に対応するデータ行を返します。
  • ユーザーがページ #2​​-10 をリクエストした場合。(page-1)*50 - (page)*50-1 の位置にある配列の id:s に対応するデータ行を返します。

数値を増やすこともできます。500 個の int:s の配列は 2K のメモリしか占有しませんが、最初のクエリ/応答をどれだけ速くしたいかによっても異なります。

私はライブ Web サイトで同様の手法を使用しました。ユーザーが 10 ページを超えて続行したときに、クエリに切り替えただけです。別の解決策は、配列を拡張/塗りつぶし続けることだと思います。(クエリを再度実行しますが、既に含まれている id:s を除外します)。

とにかく、これが役に立てば幸いです!

于 2011-10-15T04:47:50.470 に答える