Laravelには、データの取得を分割して行うためのページネーション機能が標準で3種類用意されています。それぞれ取得方法や内部クエリが異なり、適したユースケースが明確に分かれています。
1. paginate()
もっとも一般的で多機能なページネーションです。
$items = Project::query()->paginate(10);
特徴
全件数(Total Count)を取得した上でページ分割を行います。そのため、現在のページだけでなく、全体像を把握するための豊富な情報を取得できます。
-
取得できる主な情報:
- 総件数
- 現在ページ番号
- 最終ページ番号
- 次ページ・前ページの有無
メリット・デメリット
-
メリット:
- 「1 2 3 ... 20」のようなページ番号付きUIを簡単に作成できる
- ユーザーが総件数を確認できる
-
デメリット:
- 内部で
COUNTクエリが発行されるため、データ量が増えるとパフォーマンスが低下しやすい
- 内部で
向いているケース
- ページ番号を指定して遷移させたい場合
- 管理画面など、データの総数を確認する必要がある場合
2. simplePaginate()
paginate() を軽量化したバージョンです。
$items = Project::query()->simplePaginate(10);
特徴
全件数(COUNT)を取得せず、「次(または前)のデータが存在するかどうか」だけを確認します。
-
取得できる主な情報:
- 現在ページ
- 次ページの有無
- 前ページの有無
-
取得できない情報:
- 総件数
- 最終ページ番号
メリット・デメリット
-
メリット:
-
COUNTクエリが発生しないため、paginate()より動作が軽い
-
-
デメリット:
- 「全何ページ中、今何ページ目か」を表示することができない
向いているケース
- 「次へ / 前へ」だけのシンプルなナビゲーション
- 「さらに読み込む(Load More)」形式のボタン
3. cursorPaginate()
カーソルベース(ポインタ形式)のページネーションです。
$items = Project::query()->orderBy('id')->cursorPaginate(10);
特徴
page=2 のようなオフセット(飛ばし読み)ではなく、「指定したカラムの最新の値(カーソル)」を基準に次の10件を取得します。URLにはエンコードされたカーソル情報(例: ?cursor=eyJpZCI6MTB9)が含まれます。
メリット・デメリット
-
メリット:
- 大量データに対して非常に高速
-
OFFSETを使用しないため、データの追加・削除による「次ページでのデータの重複・欠け」が発生しない
-
デメリット:
- 特定のページ番号(例: 5ページ目)へ直接ジャンプすることができない
- 並び替えに使用するカラム(一意なカラムである必要がある)の指定が必須
向いているケース
- 無限スクロール(SNSのフィードなど)
- 数百万件を超えるような巨大なテーブルのページネーション
比較まとめ
| メソッド | 総件数取得 | パフォーマンス | 主なUI形式 |
|---|---|---|---|
| paginate() | ○ | 普通 | ページ番号(1, 2, 3...) |
| simplePaginate() | × | 軽い | 次へ / 前へ / さらに表示 |
| cursorPaginate() | × | 高速 | 無限スクロール |
使い分けの目安
paginate() を選ぶとき
- ページ番号を表示するUIが必要なとき
- 総件数や「全○ページ」という情報をユーザーに提示したいとき
simplePaginate() を選ぶとき
- 総件数の表示が不要なとき
- パフォーマンスを少しでも改善しつつ、シンプルな「次へ」ボタンを実装したいとき
cursorPaginate() を選ぶとき
- データ量が非常に多く、通常のページネーションでは動作が重いとき
- モバイルアプリのような無限スクロールを実装するとき
- データの更新が頻繁で、ページを跨いだ際のリロードによるズレを防ぎたいとき