ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|---|
|
基本構文
MySQL / PostgreSQL / SQLite
-- LIMIT のみ: 先頭 10 件
SELECT * FROM users LIMIT 10;
-- LIMIT + OFFSET: 11-20 件目 (1 ページ 10 件、2 ページ目)
SELECT * FROM users LIMIT 10 OFFSET 10;
-- MySQL 固有: カンマ区切り(OFFSET, LIMIT)
SELECT * FROM users LIMIT 10, 10; -- ← 同じ意味
-- ORDER BY 必須 (順序保証)
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;
Oracle (12c+)
-- FETCH NEXT 構文
SELECT * FROM users
ORDER BY id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
-- 旧 (Oracle 11g 以前)
SELECT * FROM (
SELECT t.*, ROWNUM AS rn
FROM (SELECT * FROM users ORDER BY id) t
WHERE ROWNUM <= 30
) WHERE rn > 20;
SQL Server (2012+)
SELECT * FROM users
ORDER BY id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
-- 旧 (SQL Server 2008)
SELECT TOP 10 * FROM (
SELECT TOP 30 * FROM users ORDER BY id
) t ORDER BY id DESC;
ページネーションの計算
-- ページ番号 → OFFSET 変換
-- page = 1, pageSize = 20 → OFFSET 0
-- page = 2, pageSize = 20 → OFFSET 20
-- page = 3, pageSize = 20 → OFFSET 40
-- 計算式: OFFSET = (page - 1) * pageSize
-- ページ数取得
SELECT COUNT(*) FROM users;
-- 総件数 / pageSize で切り上げ
-- 1 クエリで取得 + 件数も
SELECT *,
COUNT(*) OVER () AS total_count
FROM users
ORDER BY id
LIMIT 10 OFFSET 20;
JPA / Hibernate
// Spring Data JPA の Pageable
@GetMapping("/users")
public Page<User> list(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("id"));
return userRepository.findAll(pageable);
// → Page<User> オブジェクトに total count, page count 等含まれる
}
// JPQL で直接
@Query("SELECT u FROM User u ORDER BY u.id")
List<User> findUsers(Pageable pageable);
// EntityManager
List<User> users = em.createQuery("FROM User ORDER BY id", User.class)
.setFirstResult(20) // OFFSET
.setMaxResults(10) // LIMIT
.getResultList();
Laravel
// Eloquent
$users = User::orderBy('id')->skip(20)->take(10)->get();
// または
$users = User::orderBy('id')->offset(20)->limit(10)->get();
// 自動ページネーション
$users = User::orderBy('id')->paginate(20);
// → LengthAwarePaginator (件数 + リンク生成)
// API レスポンス向け simple paginate (件数取得なし、高速)
$users = User::orderBy('id')->simplePaginate(20);
// Blade テンプレート
{{ $users->links() }} // ページネーションリンク自動生成
Django
# views.py
from django.core.paginator import Paginator
def user_list(request):
users = User.objects.all().order_by('id')
paginator = Paginator(users, 20) # 1 ページ 20 件
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
return render(request, "users.html", {"page_obj": page_obj})
# テンプレート
{% for user in page_obj %}
{{ user.name }}
{% endfor %}
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">前へ</a>
{% endif %}
ページ {{ page_obj.number }} / {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">次へ</a>
{% endif %}
OFFSET の罠(パフォーマンス)
大量データの後半ページはOFFSET が大きくなるほど遅い:
-- OFFSET 1000000 LIMIT 10
SELECT * FROM big_table ORDER BY id LIMIT 10 OFFSET 1000000;
-- → DB は 1000010 行スキャンしてから先頭 100 万を捨てる (遅い)
-- 対処 1: カーソルベースページネーション (推奨)
-- 前ページの最後の id を覚えておく
SELECT * FROM big_table
WHERE id > 1000000 -- ← 前ページの最後の id
ORDER BY id
LIMIT 10;
-- → INDEX が効く、高速
-- 対処 2: ID で範囲指定
SELECT * FROM big_table
WHERE id BETWEEN 1000001 AND 1000100;
カーソルベースページネーション(推奨)
-- 初回
GET /api/users?limit=20
SELECT * FROM users ORDER BY id LIMIT 20;
-- レスポンス: { users: [...], next_cursor: "20" }
-- 次ページ
GET /api/users?limit=20&cursor=20
SELECT * FROM users WHERE id > 20 ORDER BY id LIMIT 20;
-- → INDEX で高速
-- 複合キーの場合
SELECT * FROM users
WHERE (created_at, id) < ('2026-05-15 12:00:00', 100) -- 前ページの最後
ORDER BY created_at DESC, id DESC
LIMIT 20;
# メリット:
# - パフォーマンス安定 (OFFSET 大きくても遅くならない)
# - INSERT が間に入っても重複・抜けなし
#
# デメリット:
# - ページ番号を直接指定できない (前後移動のみ)
# - SNS / 無限スクロール向き
大量データの効率的 SELECT (バッチ処理)
-- ❌ ダメ: OFFSET でループ
$offset = 0;
while (true) {
$rows = $db->query("SELECT * FROM big_table LIMIT 1000 OFFSET $offset");
if (empty($rows)) break;
process($rows);
$offset += 1000;
}
-- → OFFSET が大きくなるにつれて指数的に遅くなる
-- ✅ 良い: 最後の id で次バッチ
$lastId = 0;
while (true) {
$rows = $db->query("SELECT * FROM big_table WHERE id > $lastId ORDER BY id LIMIT 1000");
if (empty($rows)) break;
process($rows);
$lastId = end($rows)["id"];
}
-- → 各クエリが同じ速度
関連記事
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページ
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 Spring Frameworkのアノテーション一覧
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- PHPでのファイルアップロード方法|multipart/form-dataと$_FILES 2026-08-07 17:15:57
- PHP $_SERVERとは|DOCUMENT_ROOT・PHP_SELFなど主な要素 2026-08-07 17:15:57
- Scratchのアカウントの作り方|メールアドレスとユーザー名の登録手順 2026-08-07 17:15:57
- djangoにおけるMVCアプリケーション実装例 2026-08-07 17:15:57
- Bluetoothとは|仕組み・BLEとClassicの違い・用途 2026-08-07 17:15:57
- Spring Bootのテスト入門|@SpringBootTestとJUnitでの単体・結合テスト 2026-08-07 17:15:57
- APIキー取得方法 2026-08-07 17:15:56
- インストール方法(Windows版) 2026-08-07 17:15:56
- Java とは?言語仕様・JVM・主要フレームワーク一覧 2026-08-07 17:15:56
- 【PHPフレームワーク】Laravelの使い方 2026-08-07 17:15:56
- Scratch 作品の公開方法 2026-08-07 17:15:56
- Google OAuth 2.0 認証の実装方法 2026-08-07 17:15:56
- データベースとは?RDB / NoSQL / SQL の基礎 2026-08-07 17:15:56
- インストール(eclipseプラグイン) 2026-08-07 17:15:56
- Spring Frameworkの使い方 2026-08-07 17:15:56
コメントを削除してもよろしいでしょうか?