データベース正規化は、ひと言でこうまとめられます: 「同じ事実はただ1か所にだけ保存する。」 これを体系的に行う方法が 1NF → 2NF → 3NF です。
なぜ重要かというと — 同じ情報が複数の行に散らばっていると、1つだけ直して残りを直し忘れた瞬間にデータが矛盾してしまいます。これを 更新異常 といいます。下で実際に体験してみてください。
Prof.A の研究室が変わったのに、非正規化テーブルでは 2 行をすべて手作業で直さなければなりません。1つでも漏れると、「Prof.A は Room 301 でもあり Room 502 でもある」という矛盾が生まれます。3NF のテーブルなら、たった 1 行を直せば終わりです。
これが正規化のすべてです — あとは「どの列をどこに置けば、1か所にだけ保存されるのか」を判断するためのルールです。
関数従属 — 正規化の判断基準
正規化では、「この列はどこに依存しているのか」を考えます。これを 関数従属 といいます。
たとえば student_id → student_name は、「学生 ID がわかれば名前が決まる」という意味です。
下の図では、矢印の色に注目してください:
- 緑 = 全体キーに依存(正常)
- 黄 = キーの一部にだけ依存(部分従属 → 2NF 違反)
- 赤の点線 = 非キー列を経由して依存(推移的従属 → 3NF 違反)
黄色と赤の矢印をなくすこと = テーブルを分割すること = 正規化です。
1NF → 2NF → 3NF をまとめて見る
下で、段階ごとにテーブルがどう分割されていくかを実際にクリックしてみてください。赤いセルは、「この列はここにあってはいけない」という印です。
1NF: 1つのセルに値は1つ
1つのセルに MATH101, CS102 のように複数の値を入れると、検索もできず、JOIN もできません。
ルール: すべてのセルは原子的(1つの値)でなければならない。
phone1, phone2, phone3 のような列も同じ問題です — 値を列名の中に隠しているだけです。
2NF: 部分従属の除去
複合キー (student_id, course_id) を持つテーブルでは、student_name は student_id にしか依存しません。全体キーに依存しているのではなく、その一部にだけ依存しているわけです — これが 部分関数従属 です。
ルール: すべての非キー列は 全体キー に依存しなければならない。
部分従属があるなら、その列を取り出して別テーブルにします。
キーが単一列なら? 部分従属そのものが起こりえないので、1NF なら自動的に 2NF です。
3NF: 推移的従属の除去
Courses テーブルで instructor_office は course_id(キー)に直接依存していません。course_id → instructor_id → instructor_office という経路を通ります — つまり、非キー列が別の非キー列に依存しているのです。これが 推移的従属 です。
ルール: 非キー列は キーだけを通じて 依存しなければならない。ほかの非キー列を経由してはいけない。
解決法: instructor_office を Instructors テーブルに分離する。
暗記の代わりに、1つの問い
「すべての非キー属性は キーに、全体キーに、キーのみに 従わなければならない。」
この一文がすべてです:
- キーに = 1NF(事実がキーで識別できなければならない)
- 全体キーに = 2NF(キーの一部ではなく全体に依存)
- キーのみに = 3NF(非キー列を経由せず、キーに直接依存)
試験で正規化の問題が出たら、この問いだけを投げかけてください: 「この列は何に依存しているのか? 全体キーか、キーの一部か、それとも非キー列か?」
よくある勘違い
「3NF までやれば終わり」 — 3NF は良い出発点であって、終着点ではありません。より厳密な BCNF が必要な場合もありますし、逆に性能のためにあえて非正規化することもあります。
「テーブルはたくさん分割するほどよい」 — 正規化の目的はテーブル数を増やすことではなく、「各テーブルが1種類の事実だけを担当する」ようにすることです。分割すべき理由(従属関係)がないのに分割すると、JOIN が複雑になるだけです。
「NoSQL なら正規化は不要」 — 正規化は関係 DB 向けの用語ですが、「重複データの一貫性を保つ」という問題はどんな DB にもあります。非正規化するときも、「何を犠牲にしているのか」を理解したうえで行うべきです。
自分でチェックしてみよう
自分のプロジェクトのテーブルを1つ選んで、次を確認してみてください:
- キーが何かを書き出す。
- 各非キー列が全体キーに依存しているか、それとも一部にだけ依存しているかを確認する。→ 一部なら 2NF 違反。
- 非キー列がほかの非キー列に依存していないかを確認する。→ あれば 3NF 違反。
この 3 ステップだけで、ほとんどの正規化の問題は見つけられます。