非正規化とパフォーマンスの実務判断
非正規化 (denormalization) とは、参照性能や運用容易性を優先し、正規化により分割されたリレーションを意図的に冗長化または結合統合する設計手法であり、更新時異常のリスクと引き換えに読み取り効率を得る。
正規化した後にわざと崩す?
第3正規形 まで進めれば、 マスタが独立したテーブルに分かれて更新時異常が消える。 その代わり、データを取り出すときには複数のテーブルを結合 (JOIN) する必要がある。 テーブルが増えるほど JOIN も増える。
非正規化 は、この JOIN のコストが実運用で問題になった時に、 あえて「正規化した状態を一部だけ崩す」設計手法。 「わざと同じ情報を複数の場所に書く」ことで JOIN を減らし、読み取りを速くする。 代わりに更新時異常のリスクは戻ってくるので、それを別の仕組み (トリガー / アプリ側ロジック) で防ぐ責任も負う。
非正規化を選ぶ動機は主にこの 3 つ:
- JOIN 回数を減らしたい: 一つの参照でいくつものテーブルを JOIN する必要がある画面で、 関連情報を親テーブルにコピーしておいて JOIN を減らす。
- 読み取りが圧倒的に多い: 記事の閲覧数のように「読まれるのが多くて、書き換えは少ない」データでは、 読み取り時のシンプルさを優先する。
- 集計値の再計算が重い: リアルタイムに
COUNTやSUMを毎回計算するコストが高いなら、 事前に集計した数字を保存しておく。
典型例: 記事とコメント数
| 記事IDPK | タイトル | 投稿日 |
|---|---|---|
| A001 | SQL入門 | 2026-06-01 |
| A002 | インデックス設計 | 2026-06-15 |
| 記事IDPK | タイトル | 投稿日 | コメント数 |
|---|---|---|---|
| A001 | SQL入門 | 2026-06-01 | 23 |
| A002 | インデックス設計 | 2026-06-15 | 45 |
コメント テーブルから COUNT(*) で毎回集計するのが正規化された姿。 しかし記事一覧を大量表示する画面ではその集計が重荷になる。 そこで 記事 テーブルに コメント数 列を持たせ、コメント追加/削除のたびに更新する。この場合、更新時異常のリスクは「コメントを追加/削除した時に必ずコメント数を +1/-1 する」ことを アプリケーション層またはトリガーで保証することで吸収する。
「参照が遅い」時にまず試すのはインデックス
「参照が遅い」を解決する手段は非正規化だけではない。むしろ最初に試すのはインデックス側での対処で、 テーブル構造を触らずに済むぶん影響範囲が小さくて安全。
- カバリングインデックス: SELECT で欲しい列を全部インデックスに含めれば、テーブル本体を読まずに済む。単一テーブルの検索ならたいていこれで足りる。
- 複合インデックス: JOIN で使う外部キー列に複合インデックスを貼るだけで JOIN のコストが劇的に下がることも多い。
- クラスタ化インデックス: テーブルの物理配置を主キー順にすることで、レンジ検索の I/O を減らせる。
これらを試した上でなお足りない、かつ更新側のコストも含めて総合的に得だと判断できる時に、 初めてテーブル構造の非正規化に踏み込むのが安全な順序。
非正規化の中間解: 本体テーブルは正規化のまま、参照用の別テーブルを作る
「本体テーブルは正規化のまま維持しつつ、参照専用の別テーブルを冗長に持つ」というやり方もある。 こちらは本体の更新時異常リスクを触らずに済むので、非正規化の中では比較的安全。
- マテリアライズドビュー: JOIN や集計の結果を実体としてキャッシュしたもの。 即時更新か定期更新か、DBMS が用意する仕組みに乗って整合を保てる。
- サマリテーブル: 集計結果を専用のテーブルに保存し、バッチや ETL で定期的に更新する。 分析用途で多用される。
非正規化するかどうかの判断手順
- まずは 3NF まで正規化 する (これが基本形)
- 実際の参照パスで
EXPLAINを取って、本当にどこが遅いのかを特定する - インデックス側で解決 できないか検討する (カバリング / 複合)
- マテリアライズドビュー / サマリテーブルで解決できないか検討する
- それでも足りない場合に、限定した箇所で非正規化 (列の冗長化) を検討する
- 非正規化するなら、整合を保つ仕組み (トリガー / アプリ側ロジック / バッチ検証) を必ずセットで用意する
よくある疑問
関連トピック
- 基礎なぜ正規化が必要か
正規化されていないテーブルでは、同じ事実を複数の行に重複して持つために、挿入・更新・削除の各操作で矛盾や情報損失が発生する。この「更新時異常」を体系的に排除するのが正規化の目的である。
- 基礎関数従属性
属性 X の値が決まると属性 Y の値も一意に決まる関係を関数従属という。この概念は 1NF〜3NF、BCNF まで正規化の全ステップの判定基準になる。部分関数従属・推移関数従属など派生概念も整理する。
- 基礎キーの階層
正規化の議論に入る前に、スーパーキー・候補キー・主キーの3階層と、外部キー・代替キー・複合キーとの関係を整理する。2NF/3NF の「非キー属性」「部分従属」を語るための語彙を揃える。
もっと学びたい方へ(おすすめ書籍)
テーブル設計と正規化、パフォーマンス考慮のインデックス設計まで実務レベルで学べる定番書。第2版ではクラウド対応も強化。
実務でやりがちなSQL・DB設計のアンチパターンとその回避策を体系的に学べる。
SQLの本質的な使い方と、インデックスが効くクエリの書き方を学べる。ウィンドウ関数など現代SQLも網羅。
PostgreSQLの内部構造・ストレージ・インデックス機構を丁寧に解説。設計と運用計画の鉄則が学べる。
IPAデータベーススペシャリスト試験の総合対策書。インデックス関連は本サイトと合わせて学ぶと理解が深まる。
リレーショナルモデルの理論から、インデックス設計を含む実務で使えるSQLまで解説。
本セクションはAmazonアソシエイトのリンクを含みます。
もっと深くDBを学びたい方へ。
たいてっくが、SQL・データベース設計・パフォーマンスチューニング・ IPAデータベーススペシャリスト対策まで、1対1で学習をサポートします。まずは無料相談から。