正規化(データベース正規化)
1NF〜BCNFの正規化形式の定義と、非正規化が有効なケース・実務でのトレードオフの判断基準
データベース正規化とは、リレーショナルデータベースの設計において、データの冗長性を排除し、更新の整合性を保つために、テーブルを一定のルールに従って分解・整理するプロセスである。正規化を適用することで、同じ情報が複数箇所に散在する状態を防ぎ、データの変更が局所的に完結するような構造を実現できる。
正規化の理論的基盤を築いたのは、1970年代にIBMで関係モデルを提唱したEdgar F. Coddである。Coddは「第1正規形(1NF)」「第2正規形(2NF)」「第3正規形(3NF)」を定義し、後にRaymond F. Boyce との共同研究でさらに厳密な「ボイスコッドの正規形(BCNF)」を提案した。これらの正規形は「関数従属性」という概念を軸に、テーブル内の列間の依存関係を整理する理論的な枠組みを提供する。
正規化によって取り除かれる問題は大きく3種類ある。「更新異常(Update Anomaly)」は、同じ情報が複数行に存在するために、片方を更新しても他方に反映されない状態を指す。「挿入異常(Insertion Anomaly)」は、他の情報がなければ本来保存したいデータを登録できない状態、「削除異常(Deletion Anomaly)」は特定のレコードを削除すると意図せず別の情報まで失ってしまう状態を指す。正規化はこれらの異常を構造的に防ぐ手段として機能する。
第1正規形(1NF)
1NFの要件は、テーブルの各セルが「原子値(atomic value)」を持つことである。つまり、1つのセルに複数の値を詰め込んだり、同一の概念を表す列を繰り返したりしてはならない。
違反例として、注文テーブル に 商品名 カラムが "りんご, みかん, バナナ" という形で格納されているケースが挙げられる。このような「繰り返しグループ」を持つ設計は1NFを満たさない。正規化するには、注文と商品を別レコードとして分離し、1行1商品の構造にする必要がある。
第2正規形(2NF)
2NFは1NFを満たした上で、「部分関数従属(Partial Functional Dependency)」を除去した状態である。部分関数従属とは、複合主キーの一部にのみ依存している非キー属性が存在することを指す。
例として、(注文ID, 商品ID) を複合主キーとするテーブルに 商品名 カラムがある場合、商品名 は 商品ID だけで一意に決まるため、複合主キー全体には依存していない。これは部分関数従属であり、商品マスタ テーブルを分離して 商品ID → 商品名 の関係をそちらに移すことで2NFを達成できる。
第3正規形(3NF)
3NFは2NFを満たした上で、「推移的関数従属(Transitive Functional Dependency)」を除去した状態である。推移的関数従属とは、主キーでない列Aが別の非キー列Bを関数的に決定する(主キー → A → B という連鎖がある)状態を指す。
例として、社員テーブル に (社員ID, 部署ID, 部署名) があるとき、部署名 は 部署ID に依存しており、社員ID から直接ではなく 部署ID を経由して決まる。これを除去するには 部署テーブル を分離し、社員テーブル には 部署ID だけを残す。
ボイスコッドの正規形(BCNF)
BCNFは3NFをより厳密にした形式であり、「すべての関数従属 X → Y において、Xはスーパーキーでなければならない」という条件を課す。3NFでは非キー属性への従属が例外的に許容される場合があるが、BCNFはそれも許容しない。
実務的には3NFとBCNFの差異が現れるケースは限られるが、複数の候補キーが重複する属性を持つテーブル(例:授業スケジュールで (学生, 科目) と (学生, 教師) が候補キーになる場合)などで違いが生じる。BCNFへの分解は、場合によって関数従属性の一部が失われる(依存性保持が保証されない)点に注意が必要である。
コードレビューで着目するポイント
- 1カラムに複数値がカンマ区切りやJSON配列として詰め込まれていないか(1NF違反の兆候)
- 複合主キーを持つテーブルで、主キーの一部にしか依存しない列が存在しないか(2NF違反の兆候)
部署名やカテゴリ名などの名称系カラムが、マスタテーブルを介さず直接保持されていないか(3NF違反の兆候)- 外部キー制約が適切に設定されており、参照整合性が担保されているか
- 同じ意味を持つ情報が複数テーブルに重複して存在していないか(冗長性の確認)
- NULL値が多用されているカラムが、設計上の問題(異なる概念の混在など)を示していないか
- テーブル名・カラム名が表現する概念の粒度が適切か(過度に汎用的な命名は設計の曖昧さを示唆する)
非正規化が有効なケース
- OLAP(Online Analytical Processing)や集計・レポーティング用途では、結合コストを減らすためにあえて非正規化した幅広いテーブル(ワイドテーブル)を採用することが合理的である
- OLTP(Online Transaction Processing)では正規化が基本方針だが、読み取りが極端に多い参照系のデータ(例:商品の合計レビュー件数)については、集計用カラムをキャッシュとして保持し、非同期に更新する設計が実用的な場合がある
- マイクロサービスアーキテクチャでは、サービスをまたいだJOINができないため、各サービスが必要なデータを自前のDBに冗長に持つ設計(データの分散所有)が避けられないことがある
- データウェアハウスやBIツール向けのスタースキーマ・スノーフレークスキーマでは、分析クエリの単純化を優先し、意図的に非正規化された構造を採用する
典型的なアンチパターン
EAV(Entity-Attribute-Value)アンチパターン
属性名と値をそれぞれカラムに持つ汎用テーブル(entity_id, attribute_name, attribute_value の3カラム構成)は、スキーマを柔軟に見せるが深刻な問題を招く。型安全性がなく、特定の属性に対するクエリが複雑になり、インデックスの効きが悪い。また、RDBのリレーショナルモデルの利点をほぼ失う。本来は属性の多様性にはJSONカラムの利用やドキュメントDBへの移行を検討すべきである。
複数値を1カラムに詰め込む
タグや権限などを "admin,editor,viewer" のように文字列として1カラムに格納するパターンは、検索・更新・整合性の観点からすべて問題がある。特定のタグを持つレコードを検索するには LIKE '%tag%' のような曖昧検索が必要になり、インデックスが使えない。多対多の関係は中間テーブルで表現するのが正しい設計である。
IDのみ異なる重複テーブル
sales_2023, sales_2024 のように年度ごとにテーブルを増やしたり、user_jp, user_us のように地域ごとにテーブルを分けるパターンは、テーブル数が増えるにつれてスキーマ管理・クエリ・マイグレーションがすべて複雑になる。区分を表すカラム(year, region など)を追加した単一テーブルで管理し、パーティショニングで性能を担保する設計が適切である。
参考リソース
- E.F. Codd, “A Relational Model of Data for Large Shared Data Banks” (1970) — 関係モデルの原典論文。正規化の理論的出発点
- Joe Celko, “Joe Celko’s SQL for Smarties: Advanced SQL Programming” — SQL設計の実践的なアンチパターンと正規化について詳しく解説
- C.J. Date, “An Introduction to Database Systems” — 関係理論とBCNFを含む正規化形式の厳密な記述
- Bill Karwin, “SQL Antipatterns: Avoiding the Pitfalls of Database Programming” — EAVを含む典型的なSQLアンチパターンを体系的に解説(日本語訳あり)
- Martin Kleppmann, “Designing Data-Intensive Applications” — OLTP/OLAPの違いとデータ正規化・非正規化のトレードオフを実務観点から整理
- 1. 📄アーキテクチャスタイル
- 2. 📄ドメインモデリング
- 3. 📄モジュール分割と依存管理
- 4. 📄データモデリング
- 5. 📄API設計
- 6. 📄整合性とトランザクション
- 7. 📄非同期処理(Queue/Event)
- 8. 📄キャッシング
- 9. 📄ユーザーリサーチ
- 10. 📄情報アーキテクチャ
- 11. 📄インタラクションデザイン
- 12. 📄UX原則とヒューリスティクス
- 13. 📄アクセシビリティ(UX観点)
- 14. 📄UXメトリクス
- 15. 📄スケーラビリティ
- 16. 📄可用性とレジリエンス
- 17. 📄オブザーバビリティ
- 18. 📄環境・インフラ設計
- 19. 📄データマイグレーション
- 20. 📄セキュリティ設計原則
- 21. 📄設計原則
- 22. 📄デザインパターン(GoF)
- 23. 📄エンタープライズパターン
- 24. 📄クリーンコード
- 25. 📄リファクタリング
- 26. 📄型設計とコントラクト
- 27. 📄並行処理・マルチスレッド
- 28. 📄パフォーマンス最適化
- 29. 📄ドキュメント管理
- 30. 📄バージョン管理と開発プロセス
- 31. 📄脅威モデリング
- 32. 📄通信保護(TLS)
- 33. 📄正規化(データベース正規化)