データベースの正規化は、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に管理させることで、アプリ側のエラーを減らせます。
典型的な正規化フロー(実践手順)
- 業務要件から必要なエンティティ(学生、クラス、履修など)と属性を洗い出す。
- 各エンティティごとに候補キーを定め、1NFのチェックを行う(原子性、繰り返しの排除)。
- 複合キーの部分依存を見つけて2NFへ分解する。
- 推移的依存を見つけて3NFへ分解する。
- 性能要件に合わせて、必要に応じて部分的に非正規化する(記録は残す)。
まとめ(実務的ポイント)
- 第1〜第3正規形は、データ重複と不整合を防ぐための基本ルールです。
- 正規化は「常に正解」ではなく、整合性と性能のバランスをとることが重要です。
- 設計時には、主キー・外部キー・関数従属を明確にし、異常シナリオ(更新・挿入・削除)をチェックしてください。
- 運用で問題が出たら、インデックス設計やマテリアライズドビュー、あるいは限定的な非正規化で対処します。
正規化の理解はリレーショナル設計の基礎です。まず第1〜第3正規形をしっかり押さえ、実務では要件と性能を天秤にかけて最適な設計を選んでください。