
教授、データベース設計の勉強をしていて「正規化」って言葉に出会ったんですけど……これ、正直ピンと来ないんです。

ふむ。『なぜ正規化をするのか?』を意識してみたことはあるかい?

なんとなく、「データの整合性を取るため」という理解はありますが・・・

おお!本質は理解できているようだね。
一言でいうと正規化はデータの整理整頓をしているんだ。

データの整理整頓?!
第1章:正規化ってなに?
データベースの設計において、「正規化」はとても重要な概念です。難しそうに聞こえるかもしれませんが、簡単に言えば「情報を整理整頓する技術」です。
正規化の目的は、データの整理整頓
正規化の最も重要な目的は、コンピューターに保存される情報を、矛盾なく、重複なく、きちんと管理できるようにすることです。
なぜ重要なのか
情報が重複して保存されていると、様々な問題が起こります。
例えば: お客様の住所が複数の場所に記録されている場合を考えてみましょう。引っ越しがあった際、すべての記録を修正する必要があります。もし一つでも修正し忘れがあれば、古い住所と新しい住所が混在し、どちらが正しいか分からなくなってしまいます。
正規化を行うことで、顧客情報は「顧客テーブル」に、商品情報は「商品テーブル」に、というように適切なテーブルに分割します。これにより、同じ情報を複数の場所に持つ必要がなくなり、データの重複を排除し、一貫性を保つことができるのです。
正規化が解決する課題とは?
正規化は、データの重複が原因で起こる3つの大きな課題、総称して「更新異常(更新アノマリー)」を解決します。
正規化によってデータを適切に分割することで、これらの更新異常を防ぎ、データベースを健全な状態に保つことができます。
正規化がもたらすメリット
正規化は、一見すると面倒な作業に思えるかもしれませんが、そのメリットは非常に大きいです。
正規化は、堅牢で信頼性の高いシステムを構築するための基礎であり、データベース設計における第一歩と言えるでしょう。
第2章:正規化の鍵となる「関数従属」の理解
正規化のルールを深く理解するためには、その根幹をなす関数従属(Functional Dependency)の概念を正確に捉える必要があります。
関数従属とは?(基本の概念をシンプルに解説)
関数従属とは、簡単に言うと「ある項目の値が決まれば、別の項目の値も自動的に決まる」という関係性のことです。
以下のように表記します。
X → Y
この矢印は「Xが決まればYも決まる」という意味です。
身近な例で理解しよう
例1:社員情報
社員ID → 氏名、部署名
- 社員ID「001」なら → 田中太郎、営業部
- 社員ID「002」なら → 佐藤花子、経理部
社員IDを知れば、その人の氏名と部署が必ず一つに決まります。
例2:商品情報
商品コード → 商品名、価格
- 商品コード「A001」なら → ノートパソコン、98,000円
- 商品コード「B002」なら → マウス、1,500円
ポイント
- 左側:決め手となる項目(社員ID、商品コードなど)
- 右側:自動的に決まる項目(氏名、価格など)
- 一つの決め手に対して、結果は必ず一つだけ
部分関数従属とは?
部分関数従属とは?
部分関数従属とは、リレーションの主キー全体ではなく、その一部の属性に関数従属している非キー属性が存在する状態を指します。
例えば、主キーが {A, B}
、非キー属性が {C}
であるリレーションを考えてみましょう。
通常、主キー {A, B}
から非キー {C}
への関数従属({A, B} → C
)は成立しています。
しかし、もし {A} → C
という関数従属も成り立つとすると、これは次のような写像の連鎖があると考えられます。
{A, B} → A → C
この場合、C
は主キー {A, B}
全体にではなく、その部分集合 {A}
に関数従属していると言えます。
これが「部分関数従属」です。
具体例:「注文明細」テーブルを考え、以下のように定義されているとします。
- 主キー:
{注文ID, 商品ID}
- 非キー属性:
商品名
このとき、次の関係が成り立っているとします。
{注文ID, 商品ID} → 商品名
(主キー全体に基づく従属){商品ID} → 商品名
(主キーの一部に基づく従属)
この場合、商品名
は主キーの一部である 商品ID
に依存しており、これはまさに「部分関数従属」の状態です。
推移的関数従属とは?
推移的関数従属とは、主キー以外の非キー属性から、さらに別の非キー属性に関数従属している状態です。
主キーを{A}
とし、非キー属性を{B, C}
とします。
正規の関数従属として{A} → {B}
と{A} → {C}
が成り立っています。
しかし、もしここで{B} → {C}
という関係も成り立っている場合、{A} → B → C
という推移的な写像の連鎖が存在していることになります。
具体例: 社員テーブルに 社員ID
を主キーとし、部署名
と部署電話番号
という非キー属性があるとします。
{社員ID} → {部署名}
{社員ID} → {部署電話番号}
{部署名} → {部署電話番号}
この場合、部署電話番号
は社員ID
から直接決まるだけでなく、部署名
という別の非キー属性を経由しても決まります。この状態が推移的関数従属です。
第3章:第1〜第3正規形の解説
正規化の目的と関数従属の概念を理解したところで、いよいよ具体的な正規化のステップを見ていきましょう。正規化は通常、第1正規形、第2正規形、第3正規形の順に進めていきます。
第1正規形:表として扱うためのルール
第1正規形(1NF)は、リレーション(テーブル)が満たすべき最も基本的なルールです。これは、データベースの「表」として機能するための最低限の条件と言えます。
第1正規形の要件は以下の通りです。
【第1正規形】
・リレーションRのすべての属性が、スカラ値である
スカラ値というのは、「1つの値」ということです。
1NFへの正規化の例
以下の「顧客注文管理テーブル」を見てください。
注文ID | 顧客名 | 顧客住所 | 顧客電話 | 商品リスト | 価格リスト | 数量リスト | 合計金額 |
---|---|---|---|---|---|---|---|
001 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | ノートPC,マウス | 80000,2000 | 2,1 | 162000 |
002 | 佐藤物産 | 大阪府大阪市2-2-2 | 06-9876-5432 | キーボード | 5000 | 3 | 15000 |
003 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | ディスプレイ,マウス | 30000,2000 | 1,2 | 34000 |
これを第1正規形にするためには、繰り返し項目をなくし、1行が1つの保有資格を表すように分解します。
注文ID | 顧客名 | 顧客住所 | 顧客電話 | 商品名 | 価格 | 数量 |
---|---|---|---|---|---|---|
001 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | ノートPC | 80,000 | 2 |
001 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | マウス | 2,000 | 1 |
002 | 佐藤物産 | 大阪府大阪市2-2-2 | 06-9876-5432 | キーボード | 5,000 | 3 |
003 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | ディスプレイ | 30,000 | 1 |
003 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | マウス | 2,000 | 2 |
この新しいテーブルは、1つのセルが1つの原子的な値を持つため、第1正規形を満たします。
第2正規形:部分関数従属の排除
第2正規形(2NF)の要件は以下の通りです。
【第2正規形】
・第1正規形であること
・候補キーに部分関数従属する非キー属性が存在しないこと
先ほどの第1正規形を満たしたテーブルを見てみましょう。このテーブルの主キーは、「注文ID」と「商品名」です。
注文ID | 顧客名 | 顧客住所 | 顧客電話 | 商品名 | 価格 | 数量 |
---|---|---|---|---|---|---|
001 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | ノートPC | 80,000 | 2 |
001 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | マウス | 2,000 | 1 |
002 | 佐藤物産 | 大阪府大阪市2-2-2 | 06-9876-5432 | キーボード | 5,000 | 3 |
003 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | ディスプレイ | 30,000 | 1 |
003 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 | マウス | 2,000 | 2 |
このテーブルでは、
- 「顧客名」、「顧客住所」、「顧客電話」は注文IDだけで決まる
- 「価格」は商品名だけで決まる
これは部分関数従属です。
2NFへの正規化の例
部分関数従属を排除するには、従属関係にある属性を別のテーブルに分離します。
注文テーブル
注文ID | 顧客名 | 顧客住所 | 顧客電話 |
---|---|---|---|
001 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 |
002 | 佐藤物産 | 大阪府大阪市2-2-2 | 06-9876-5432 |
003 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 |
商品テーブル
商品名 | 価格 |
---|---|
ノートPC | 80,000 |
マウス | 2,000 |
キーボード | 5,000 |
ディスプレイ | 30,000 |
注文明細テーブル
注文ID | 商品名 | 数量 |
---|---|---|
001 | ノートPC | 2 |
001 | マウス | 1 |
002 | キーボード | 3 |
003 | ディスプレイ | 1 |
003 | マウス | 2 |
- 「注文テーブル」を作成
主キーの一部である「注文ID」と、それに従属する「顧客名」「顧客住所」「顧客電話」を抜き出します。 - 「商品テーブル」を作成
主キーの一部である「商品名」と、それに従属する「価格」を抜き出します。 - 「注文明細テーブル」を作成
主キーと、抜き出されなかった属性「数量」でテーブルを作成する。
これで、3つのテーブルはそれぞれ第2正規形を満たしました。
第3正規形:推移的関数従属の排除
第3正規形(3NF)の要件は以下の通りです。
第3正規形
・第2正規形であること
・候補キーに推移的関数従属する非キー属性が存在しないこと
先ほど第2正規形にした、注文テーブルを見てみましょう。主キーは「商品ID」です。
注文ID | 顧客名 | 顧客住所 | 顧客電話 |
---|---|---|---|
001 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 |
002 | 佐藤物産 | 大阪府大阪市2-2-2 | 06-9876-5432 |
003 | 田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 |
このテーブルでは、以下の関数従属が成り立っています。
- 注文ID → 顧客名 → 顧客住所、顧客電話
顧客住所と顧客電話は、直接的には顧客名に依存し、注文IDには間接的に依存しています。
これは推移的関数従属です。
3NFへの正規化の例
推移的関数従属を排除するには、この従属関係にある属性を別のテーブルに分離します。
- 「顧客テーブル」を作成
非キー属性である「顧客名」と、それに従属する「顧客住所」「顧客電話」を抜き出します。 - 「商品テーブル」を作成
元のテーブルから「顧客住所」「顧客電話」を削除します。
顧客テーブル
顧客名 | 顧客住所 | 顧客電話 |
---|---|---|
田中商事 | 東京都渋谷区1-1-1 | 03-1234-5678 |
佐藤物産 | 大阪府大阪市2-2-2 | 06-9876-5432 |
注文テーブル
注文ID | 顧客名 |
---|---|
001 | 田中商事 |
002 | 佐藤物産 |
003 | 田中商事 |
第4章:まとめ
本記事では、正規化の前提となる**「関数従属」**の概念を出発点に、第1正規形・第2正規形・第3正規形の内容を、具体例を交えながら解説しました。
正規化で得られるメリット
✅ データの重複排除
✅ 更新時の不整合防止
✅ 健全なデータベース設計
ただし、正規化すればするほど良いというわけでもありません。
適切なレベルでの正規化が、実用的なデータベース設計の鍵となります。
次回は、「正規化の実践編」として、以下の内容を詳しく解説します:
- それぞれの正規化によって何がうれしいのか
- 逆にどんな不都合が生じるのか
- 実践的な判断基準
データベース設計に悩んでいる方や、設計の意図をより深く理解したい方は、ぜひ次回もご覧ください!