SQL でクエリを実行するときにサイトのページネーションを行う最も効率的な方法は何ですか?
質問
Web ページで使用する SQL クエリの結果をページ分割しようとしています。言語とデータベース バックエンドは PHP と SQLite です。
私が使用しているコードは次のように機能します(ページ番号は0から始まります)
http://example.com/table?page=0
page = request(page)
per = 10 // results per page
offset = page * per
// take one extra record so we know if a next link is needed
resultset = query(select columns from table where conditions limit offset, per + 1)
if(page > 0) show a previous link
if(count(resultset) > per) show a next link
unset(resultset[per])
display results
これより効率的にページネーションを実行する方法はありますか?
現在の方法でわかっている問題の 1 つは、表示を開始する前に 10 個 (またはいくつでも) の結果をすべてメモリに保存する必要があることです。PDO では行数が利用可能であることが保証されないため、これを行います。
を発行した方が効率的ですか? COUNT(*)
クエリを実行して存在する行数を確認し、結果をブラウザにストリーミングしますか?
これは、テーブルのサイズと、 count(*)
クエリにはデータベース バックエンドでのフル テーブル スキャンが必要です」、「プロファイリングを自分で実行してください」といった質問はありませんか?
解決
まずは数えてみることをお勧めします。count(主キー) は非常に効率的なクエリです。
他のヒント
COUNT(*) two クエリ メソッドを使用することにしました。これにより、他のメソッドでは許可されない最後のページへの直接リンクを作成できるからです。最初にカウントを実行すると、結果をストリーミングすることもできるため、少ないメモリでより多くのレコードを処理する場合にうまく機能するはずです。
ページ間の一貫性は私にとっては問題ではありません。助けてくれてありがとう。
非常に複雑な (9 ~ 12 テーブル結合) クエリがあり、ページ分割する必要がある数千行を返すケースがいくつかあります。明らかに、適切にページ分割するには、結果の合計サイズを知る必要があります。MySQL データベースでは、SELECT で SQL_CALC_FOUND_ROWS ディレクティブを使用すると、これを簡単に実現できますが、それがより効率的かどうかについてはまだ結論が出ていません。
ただし、SQLite を使用しているため、2 つのクエリのアプローチに固執することをお勧めします。 ここ この問題に関する非常に簡潔なスレッドです。
バックエンドが 10 行を返すのをユーザーが待つことが問題になるとは思えません。(画像のサイズを指定するのが上手になったり、可能な場合は Web サーバーに圧縮されたデータ転送をネゴシエートさせたりすることで、問題を補うことができます。)
最初に count(*) を実行することはあまり役に立たないと思います。
複雑なコーディングを行っている場合:ユーザーがページ x を見ているときに、ajax のようなマジックを使用してページ x+1 をプリロードし、ユーザー エクスペリエンスを向上させます。
ページネーションに関する一般的な注意:ユーザーがページを閲覧している間にデータが変更された場合、 5月 ソリューションに非常に高いレベルの一貫性が要求される場合には問題になります。それについてメモを書きました 他の場所で.