ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子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 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 オブジェクトに total count, page count 等含まれる
}
// JPQL で直接
@Query("SELECT u FROM User u ORDER BY u.id")
List findUsers(Pageable pageable);
// EntityManager
List 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 %}
前へ
{% endif %}
ページ {{ page_obj.number }} / {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
次へ
{% 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 と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Laravel キャッシュクリア完全ガイド(cache:clear / config:clear / 2026-05-18 07:42:07
- プロジェクトの作成と削除 2026-05-18 07:42:07
- インストール直後にNetbeansが反応しない 2026-05-18 07:42:07
- 動画やチャンネルの検索 2026-05-18 07:42:07
- APIキー取得方法 2026-05-18 07:42:07
- チャンネル情報の取得 2026-05-18 07:42:07
- API 入門 — Web API(REST / GraphQL / gRPC / 2026-05-18 07:42:07
- インストール(eclipseプラグイン) 2026-05-18 07:42:07
- Laravel「Dotenv values containing spaces must be surrounded 2026-05-18 07:42:07
- エラー一覧 2026-05-18 07:42:07
- curl: (51) SSL: certificate subject name '~' does not match 2026-05-18 07:42:07
- インストール方法(Windows版) 2026-05-18 07:42:07
- JSONから配列に変換 2026-05-18 07:42:07
- 処理を一定時間待つ 2026-05-18 07:42:07
- A non well formed numeric value encountered 2026-05-18 07:42:07
コメントを削除してもよろしいでしょうか?