ページ送り (ページネーション) はどう作りますか

OFFSET 方式は簡単だが深いページで遅く、途中で行が足されると重なりや抜けが出る。カーソル方式は最後に見た行から次を取るので、大量のデータや無限スクロールに強い、と比べて答える問い。

答えてみる

面接官に「ページ送り (ページネーション) はどう作りますか」と聞かれたつもりで、答えを見る前に自分の言葉で答えます。

声に出して答えた人は「書かずに答えを見る」で開けます。

解説を読む

聞かれ方から関連するコースまで、この問いの解説を全部ここに置いています。

こう聞かれます

  • 「ページ送り (ページネーション) はどう作りますか」
  • 「OFFSET を使ったページ送りで、何が困りますか」
  • 「無限スクロールの一覧では、どう取りますか」

面接官が見ている点

  • OFFSET 方式とカーソル方式の 2 つを知っていて、違いを説明できるか
  • OFFSET が深いページで遅くなる理由 (飛ばす行も読んでいる) を言えるか
  • 途中で行が足されたときに、重なりや抜けが出ることに気づいているか
  • 並べる順が一意になるよう、id などで同点を崩すことを知っているか

短い答え

  • OFFSET 方式 (何件飛ばして何件取るか) は簡単で、「5 ページ目へ飛ぶ」もできますが、深いページほど遅くなり、途中で行が足されると重なりや抜けが出ます。
  • カーソル方式は、「最後に見た行の日時と id より後」を条件に次を取るので、どのページでも速く、途中で行が足されてもずれません。
  • 管理画面のようにページの番号で飛びたい所は OFFSET、データが多い一覧や無限スクロールはカーソル方式、と使い分けます。

少し詳しい答え

OFFSET 方式

SQL クエリ

SELECT id, title, created_at
FROM posts
ORDER BY created_at DESC, id DESC
LIMIT 20 OFFSET 40;  -- 3 ページ目

ページの番号から OFFSET を計算するだけなので、作るのは簡単です。全体の件数を数えれば、「全何ページ」も出せます。

弱点は 2 つあります。

  • 深いページほど遅い DB は、飛ばす行も一度並べて読んでから捨てます。OFFSET が大きいほど読む量が増えます
  • 途中の追加でずれる 1 ページ目を見ている間に新しい行が 1 件足されると、全体が 1 件ずつ後ろへずれ、2 ページ目の頭に、1 ページ目の最後の行がもう一度出ます。消されたときは逆に 1 件抜けます

カーソル方式

最後に見た行の値を覚えておき、「それより後」を取ります。

SQL クエリ

SELECT id, title, created_at
FROM posts
-- $1 と $2 は、前のページの最後の行の created_at と id
WHERE (created_at, id) < ($1, $2)
ORDER BY created_at DESC, id DESC
LIMIT 20;

並べる順の列にインデックスがあれば、DB は目印の位置から 20 件だけ読めばよいので、何ページ目でも速さがほぼ変わりません。途中で行が足されても、目印より後ろを取るだけなので、重なりも抜けも出ません。

並べる列が日時だけだと、同じ時刻の行がいくつもあるときに順が決まらず、境目で抜けが出ます。id のような一意の列を後ろに足して、順を 1 つに決めます。この 2 つの列を合わせた複合インデックスを作っておきます。

API では、次のページの目印を、中身を気にせず渡せる文字列 (カーソル) にして返し、クライアントはそれを次の呼び出しに付けます。

http

GET /posts?limit=20&cursor=eyJjcmVhdGVkX2F0Ijoi

トレードオフ

カーソル方式にも弱点があります。「5 ページ目へ飛ぶ」ことができず、前へ戻るにも逆向きの問い合わせが要ります。並べ方を利用者が自由に変えられる画面では、並べ方ごとに目印とインデックスを考える必要があり、作りが重くなります。

だから、行が少なく、ページの番号で飛びたい管理画面は OFFSET のままでよく、データが多い、新しい行がどんどん足される、無限スクロールで次々読む、という一覧はカーソル方式にします。

話すときは、自分が作った一覧の画面を 1 つ選び、どちらの方式にしたか、件数がどれくらいで、なぜその方式にしたかを話せるようにしておきます。

よくある間違い

  • ORDER BY を付けずに LIMIT と OFFSET を使う並べる順が決まらないので、ページごとに行が重なったり抜けたりします
  • 日時だけで並べる同じ時刻の行があると順が決まりません。id を後ろに足します
  • どの一覧も OFFSET で作るデータが増えると、深いページが遅くなります。件数と使い方を見て選びます

深掘りの問い

  • 「全何件か、を毎回数えると何が困りますか」件数が多いと COUNT が重くなるので、おおよその件数で済ませる、件数を出さず「次があるか」だけ返す、などを挙げます
  • 「次のページがあるかは、どう分かりますか」欲しい件数より 1 件多く取り、多く取れたら次がある、と判断する、と答えます
  • 「カーソルの中身を利用者に見せてよいですか」中身に頼られないよう、符号化した文字列として渡し、サーバー側で読み直して確かめる、と答えます

確認日 2026年10月24日

技術面接問題の一覧へ戻る