こう 聞かれます
- 「ページ
送り (ページネーション) は どう 作りますか」 - 「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 ページ目ページの
弱点は 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;並べる
並べる
API では、
http
GET /posts?limit=20&cursor=eyJjcmVhdGVkX2F0Ijoiトレードオフ
カーソル方式にも
だから、
話すときは、
よく ある間違い
- ORDER BY を
付けずに LIMIT と OFFSET を使う 並べる 順が 決まらないので、 ページごとに 行が 重なったり抜けたりします - 日時だけで並べる
同じ 時刻の 行が あると 順が 決まりません。 id を 後ろに足します - どの
一覧も OFFSET で作る データが 増えると、 深い ページが 遅くなります。 件数と 使い方を 見て選びます
深掘りの問い
- 「全何件か、を
毎回数えると 何が 困りますか」 件数が 多いと COUNT が 重くなるので、 おおよ その 件数で 済ませる、 件数を 出さず 「次があるか」だけ返す、 などを挙げます - 「次の
ページが あるかは、 どう 分かりますか」 欲しい 件数より 1 件多く 取り、 多く 取れたら次が ある、と 判断する、と答えます - 「カーソルの
中身を 利用者に 見せて よいですか」 中身に 頼られないよう、 符号化した 文字列として 渡し、 サーバー側で 読み直して 確かめる、と答えます