データモデル設計ガイド
設計時にインデックスを考える理由 — 後付けが高コストになる
「遅くなったら貼る」では間に合わない。設計時にどのクエリをどの索引で支えるかを決める。
なぜ「設計時に」インデックスを考えるのか
インデックスの入門記事ではよく「まず動かしてから、遅いところに貼る」と書かれます。初期開発ではそれでも動きますが、本番のテーブルが育ってから貼り直すと高コストです。この前提を共有しておくと、以降のページの意味が変わります。
設計時に意識したいのは、次のような「インデックスによって形が決まる判断」がテーブル設計とほぼ同時に発生することです。
- 主キーの選び方 — 代理キー / 自然キー / UUID v4 / UUID v7 / BIGINT は、そのまま最大のインデックス(PK index)設計に直結する
- クエリで使う列の並び — 複合インデックスの先頭列は設計図の段階で決まっている(ユーザー別タイムライン / テナント別検索など)
- 論理削除・マルチテナント —
deleted_at IS NULLやtenant_id = ?を全クエリに乗せる設計は、インデックスの先頭列 or 部分インデックスが前提 - ソート・ページネーション —
ORDER BY created_at DESC LIMIT 20のような典型クエリが想定されるなら、その時点で複合インデックスの形が決まる
つまりインデックス設計は「性能対策」ではなく、テーブル設計の一部です。このシリーズでは、設計フェーズで決めておくべきインデックスの型を 9 ページで整理していきます。
後付けが高コストになる 4 つの局面
「後から貼ればいい」が通用しづらい代表ケースを押さえておきます。設計レビューでこれらを避けられているか確認しましょう。
| 局面 | 具体的に何が起きるか | 設計時にやるべきこと |
|---|---|---|
| 1. 巨大テーブルの ALTER | 数千万〜億行に CREATE INDEX すると、MySQL 8 以前では長時間のテーブルロック、新しい版でも I/O ピーク・レプリ遅延が発生 | 業務で「一覧」「検索」に使う列の索引は初期 DDL に含める |
| 2. 主キーは変えにくい | PK を変えると全 FK・全アプリコード・外部システム連携・URL の ID 等が連鎖変更。UUID v4 → v7 でさえ影響が出る | PK 方針は最初の 1 回で決める(主キー設計) |
| 3. 分散 / レプリ環境 | レプリカへの DDL 伝搬・オンライン DDL ツール(pt-online-schema-change, gh-ost)のセットアップ・ダウンタイム調整が必要 | 初期段階でホットパスのインデックスを揃え、あとから追加する回数を減らす |
| 4. 後から気づく UNIQUE | データが汚れてから UNIQUE を貼ろうとすると、既存重複の洗浄が必要。本番のデータクレンジングは事故と工数の温床 | 業務キーの一意性は初期 DDL で UNIQUEを付ける |
PostgreSQL の CREATE INDEX CONCURRENTLY や MySQL 8.0 の online DDL は救いではありますが、「やらずに済む」選択肢の方が常に安いです。
クエリパターンから逆算する設計プロセス
インデックスを設計時に決める実務的な手順は、次の逆算です。難しい話ではなく、単にやる/やらないで大きな差になります。
- ユースケースごとに想定 SQL を列挙 — 「ユーザーの注文一覧を新着順で 20 件」「テナント × ステータスで絞り込み」など、典型クエリを文章で書き出す
- 各 SQL の
WHERE/JOIN/ORDER BYに出てくる列を列挙 — これが索引候補 - 等値 → 範囲 → ソート の順に並べて複合インデックスの型を決める(列順設計)
- 共通列(
tenant_id/deleted_at)を先頭に寄せるか、部分インデックスにするか判断(部分・式インデックス) - FK 列はすべて索引に入る設計か確認(MySQL は自動、PostgreSQL は手動 — FK のインデックス)
- 合計本数が 1 テーブル 5〜7 本以内に収まるか(書き込みコスト)
クエリパターンが未確定の画面は、無理に索引を決める必要はありません。確定しているクエリだけで設計を進め、未確定分は「計測してから足す」のが現実解です。
このシリーズの読み方
以降のページは、設計の流れに沿って読めるように並べています。用途に応じて拾い読みでも構いません。
- インデックス種別の選び方 — B-Tree / Hash / GIN / GiST / BRIN の使い分け
- 主キー設計とクラスタリング — InnoDB の clustered index という特殊事情
- 複合インデックスの列順設計 — 等値 → 範囲 → ソート
- カバリングインデックス戦略 — INCLUDE 列の選び方
- 外部キー・リレーション列のインデックス
- 部分インデックス・式インデックス
- ページネーション・ソートのためのインデックス
- トレードオフと設計レビュー
既に動いているクエリを速くしたい場合は、チューニング側の インデックス入門 / 実行計画の読み方 から入る方が近道です。
