データベースの正規化は、1970年代にエドガー・F・コッドによって導入されたデータベース設計のアプローチです。リレーショナル・データベースとして知られる特定のデータベースでは、データを別々のグループに格納することができます。各グループは一般的にテーブルと呼ばれています。有用な情報を提供するために、これらのグループは互いに接続されています。例えば、学生はあるグループに保存され、クラスは別のグループに保存されます。学生がクラスに在籍していることを示すために、あるグループから他のグループへの「関係」が確立されます。学生とクラスの関係は、一対多多対多といった形で表現できます(例:ある学生は複数のクラスを履修し、あるクラスには複数の学生が在籍する、など)。

伝統的な代替案としては、スプレッドシートのようにすべてのデータがまとめられている「フラットファイルデータベース」があります。フラットファイルデータベースの問題点は、空欄が多く、各エントリごとに繰り返さなければならない情報が多いことです。これは、データベースが必要以上に大きくなることを意味し、データベースに間違いが含まれる可能性が高くなることを意味します。リレーショナルデータベースは、データをグループに分割することで、ミスが起こる可能性を減らし、必要以上にスペースを取らないようにしています。しかし、それが機能するためには、適切な設計が不可欠です。

データベースの正規化は、良いリレーショナルデータベースを設計するための体系的な方法です。いくつかの「正規形(Normal Form)」があり、それぞれにデータベースが満たすべきルールがあります。コッドは元々、異なるデータベースが満たすべき基準として第1、第2、第3の正規形(1NF, 2NF, 3NF)を提唱しました。ここでは第1〜第3正規形の基礎と、なぜ正規化が重要かを分かりやすく解説します。

なぜ正規化するのか(目的と効果)

  • データの一貫性(整合性)を保つ:重複を減らすことで、同一のデータが複数箇所で矛盾するリスクを下げます。
  • 異常(アノマリー)の防止:更新・挿入・削除時の不整合(更新異常、挿入異常、削除異常)を避けやすくなります。
  • 保存効率の向上:不要な繰り返しデータを排除してストレージを節約します。
  • 設計の明確化:テーブルと関係(外部キー)を明確にすることで、システムの理解と保守がしやすくなります。

第1正規形(1NF) — 基本ルール

  • 各列の値は原子的(不可分)であること:1つのセルに複数の値(カンマ区切りのリストなど)を入れない。
  • 行は一意に識別できること:プライマリキー(単一または複合)で行を特定できる。
  • 繰り返しグループを排除:同じ属性の繰り返し列を持たない。

例:学生テーブルに「履修科目1」「履修科目2」...と列を増やすのは1NFに反します。代わりに履修(enrollment)という別テーブルで学生IDとクラスIDを組にして管理します。

第2正規形(2NF) — 部分関数従属の排除

  • テーブルが1NFを満たすこと
  • 複合主キーの一部にのみ依存する属性を排除:主キーが複数列からなる場合、その一部だけに依存する列があってはならない。

例:履修テーブル(学生ID, クラスID)が主キーで、そこに「学生名」が含まれていると、学生名は学生IDだけで決まる(部分依存)ため不適切です。学生名は学生テーブルに移すべきです。

第3正規形(3NF) — 推移的関数従属の排除

  • テーブルが2NFを満たすこと
  • 非キー属性同士の依存(推移的依存)を排除:キー→A→B のように、キーから直接決まらない属性を持たない。

例:従業員テーブルに「部署ID」と「部署名」があり、「部署名」が部署IDで決まる場合、部署名は部署テーブルに分離すべきです。そうすることで従業員テーブルはキーから直接決まる属性のみを持ちます。

重要な概念:関数従属と主キー

  • 関数従属(Functional Dependency):ある属性集合の値が別の属性の値を一意に決定する関係。書き方は A → B(AがわかればBが決まる)。
  • 主キー(Primary Key):各行を一意に特定するための属性または属性の組み合わせ。候補キー、外部キー(別テーブルの主キーを参照)も理解しておきます。

正規化と実務での注意点

  • 利点と欠点のトレードオフ:正規化はデータ整合性を高めますが、ジョインが増えるため読み取り性能が低下することがあります。大量読み取りの用途では意図的に正規化度合いを下げ(非正規化)、パフォーマンスを優先することもあります。
  • インデックスと物理設計:正規化は論理設計の指針であり、実装時にはインデックスやパーティショニング、キャッシュ、マテリアライズドビューなどで性能を補います。
  • サロゲートキー vs 自然キー:実務では一意な番号(ID)を主キーにすることが多く、意味のある列(例:メールアドレス)は候補キーやユニーク制約として扱われます。
  • 外部キー制約の活用:参照整合性をDBMSに管理させることで、アプリ側のエラーを減らせます。

典型的な正規化フロー(実践手順)

  1. 業務要件から必要なエンティティ(学生、クラス、履修など)と属性を洗い出す。
  2. 各エンティティごとに候補キーを定め、1NFのチェックを行う(原子性、繰り返しの排除)。
  3. 複合キーの部分依存を見つけて2NFへ分解する。
  4. 推移的依存を見つけて3NFへ分解する。
  5. 性能要件に合わせて、必要に応じて部分的に非正規化する(記録は残す)。

まとめ(実務的ポイント)

  • 第1〜第3正規形は、データ重複と不整合を防ぐための基本ルールです。
  • 正規化は「常に正解」ではなく、整合性と性能のバランスをとることが重要です。
  • 設計時には、主キー・外部キー・関数従属を明確にし、異常シナリオ(更新・挿入・削除)をチェックしてください。
  • 運用で問題が出たら、インデックス設計やマテリアライズドビュー、あるいは限定的な非正規化で対処します。

正規化の理解はリレーショナル設計の基礎です。まず第1〜第3正規形をしっかり押さえ、実務では要件と性能を天秤にかけて最適な設計を選んでください。