0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

表(データベースのテーブル)の正規化

Posted at

0. 正規形(Normal Form)、正規化(Normalization)とは

正規形(Normal Form) とは、リレーショナルデータベースにおける表(テーブル)の構造が、どの程度「整っている」かを表す基準です。
「第1正規形」「第2正規形」「第3正規形」「第4正規形」「第5正規形」と段階があり、数字が大きいほど冗長性や不整合が減り、より良いデータ構造になっていきます。

  • 第1正規形(1NF)原子値 のみを持ち、繰り返しや複数値を持たない(1セル1値)
  • 第2正規形(2NF):主キーの一部だけに依存する 部分関数従属 を排除
  • 第3正規形(3NF):主キー以外の列が他の非キー列に依存する 推移的関数従属 を排除
  • 第4正規形(4NF)多値従属を排除
  • 第5正規形(5NF)不要な結合従属 を排除

正規化(Normalization) とは、テーブルを正規形に従って分割・整理する手続きのことです。

正規化することはメリットが大きいですが、デメリットもあります。

  • 正規化のメリット
    • データの冗長性を減らせる
    • 更新の整合性が保たれる
    • 削除や追加で矛盾が起こりにくい
    • データの一貫性・整合性が高まる
    • データの再利用性が高い
  • 正規化のデメリット
    • テーブル数が増える
    • クエリが複雑になる
    • パフォーマンス低下の可能性
    • 設計と理解が難しくなる
    • 分析用途には不向きな場合がある

正規化すると 「データの整合性と冗長性削減」 には強くなりますが、「パフォーマンスや扱いやすさ」 では弱くなることもあります。
実務では「第3正規形くらいまで正規化した上で、必要に応じて非正規化する」とすることが多いかもしれません。

1. 第1正規形 (first normal form; 1NF)

以下の条件を満たすものが 第1正規形(1NF) となります。

  • すべての属性値は「原子値」(分割できない値)である
  • 1つのセルに複数の値や繰り返しのグループを持たない

1.1. 第1正規化(1NF)とは

繰り返し属性を排除し、全ての列が 原子値(分解不可能な最小単位の値) を持つようにします。
つまり、1つのセルに複数の値を入れてはならず、1つのセルに1つの値を入れるようにします。

1.2. 第1正規化(1NF)の例

第1正規化されていない例(非正規形)
社員ID 氏名 電話番号
1 佐藤 090-1111-1111, 03-1234-5678
2 鈴木 080-2222-2222
3 高橋 070-3333-3333, 03-9876-5432

電話番号が「カンマ区切りで複数入っている」ため、1セルが原子値ではなく、繰り返し属性を含んでいます。

第1正規化済みの例(1NF)

電話番号を1つの行に1つずつ持たせます。

社員ID 氏名 電話番号
1 佐藤 090-1111-1111
1 佐藤 03-1234-5678
2 鈴木 080-2222-2222
3 高橋 070-3333-3333
3 高橋 03-9876-5432

これで「1セルに1つの値」となり、1NFが満たされます。

2. 第2正規形 (second normal form; 2NF)

以下の条件を満たすものが 第2正規形(2NF) となります。

  • 第1正規形(1NF) を満たしている
  • 部分関数従属 を排除している(つまり、主キーが 複合キー の場合、非キー属性がキーの一部にのみ依存していない)

2.1. 第2正規化(2NF)とは

部分関数従属 を排除します。
主キーが 複合キー の場合、主キーの一部の列にだけ依存している属性を別テーブルに分けます。
要するに、主キー全体に依存しない列を分離します。

2.2. 第2正規化(2NF)の例

第2正規化されていない例

社員とプロジェクトと役割を管理する表を考えます。

社員ID プロジェクトID 社員名 プロジェクト名 役割
1 A 佐藤 会計システム 開発
2 A 鈴木 会計システム テスト
1 B 佐藤 在庫管理 開発
3 B 高橋 在庫管理 設計
  • 主キー(候補)は「社員ID」「プロジェクトID」となっている
  • 「社員名」は「社員ID」にだけ依存しており、「プロジェクトID」には依存していない
  • 「プロジェクト名」は「プロジェクトID」にだけ依存しており、「社員ID」には依存していない

つまり「部分関数従属」が発生しているので 2NF違反 となっています。

第2正規化済みの例(2NF)

依存関係に基づいてテーブルを分けます。

1. 社員テーブル

社員ID 社員名
1 佐藤
2 鈴木
3 高橋

2. プロジェクトテーブル

プロジェクトID プロジェクト名
A 会計システム
B 在庫管理

3. 社員×プロジェクト テーブル(役割を保持)

社員ID プロジェクトID 役割
1 A 開発
2 A テスト
1 B 開発
3 B 設計

これで「社員名」は「社員テーブル」、「プロジェクト名」は「プロジェクトテーブル」に移され、「社員×プロジェクトの関係表」には複合キーに完全従属する「役割」だけが残るので、2NF を満たします。

3. 第3正規形 (third normal form; 3NF)

以下の条件を満たすものが 第3正規形(3NF) となります。

  • 第2正規形(2NF) を満たしている
  • 推移的関数従属 を排除している(つまり、非キー属性は主キーにのみ依存し、非キー属性が他の非キー属性に依存していない)

3.1. 第3正規化(3NF)とは

推移的関数従属 を排除します。
2NFでは「主キーの一部にしか依存しない属性(部分関数従属)」を排除しました。
3NFでは「主キーではない列に依存している列(推移的従属)」を排除します。
つまり、主キー以外の列に依存している列を別テーブルに分けます。

3.2. 第3正規化(3NF)の例

第3正規化されていない例

例えば以下の「社員テーブル」があるとします。

社員ID 社員名 部署ID 部署名
1 佐藤 10 経理部
2 鈴木 10 経理部
3 高橋 20 開発部

主キーは「社員ID」、「部署名」は「部署ID」に依存しています。
つまり「社員ID → 部署ID → 部署名」という 推移的関数従属 が発生しており、これが 3NF違反 です。

第3正規化済みの例(3NF)

「部署情報」を独立させて、推移的従属を解消します。

1. 社員テーブル

社員ID 社員名 部署ID
1 佐藤 10
2 鈴木 10
3 高橋 20

2. 部署テーブル

部署ID 部署名
10 経理部
20 開発部

これで「社員テーブル」は「社員情報+部署ID」だけを持ち、「部署名」は「部署テーブル」に任せる形となり、3NF を満たします。

4. 第4正規形 (fourth normal form; 4NF)

1つのテーブルに 独立した複数の繰り返し属性(多値属性) を持たせないようにします。
複数値の属性が互いに独立している場合、別テーブルに分けます。

4.1. 第4正規化(4NF)とは

以下の条件を満たすものが 第4正規形(4NF) となります。

  • 第3正規形(3NF) を満たしている
  • 多値従属 を排除している(つまり、1つのキーに対して、独立した複数の属性が繰り返される場合、それぞれを別のテーブルに分けられている)

4.2. 第4正規化(4NF)の例

多値従属を排除します。
3NFまでは、キーに対する関数従属を整理しました。
4NFでは、1つのキーに対して、互いに独立した複数の繰り返し項目(多値従属)がある場合に、それを分けます。
要するに「1つの主キーに対して、複数の独立したリストを同じ表に入れない」というルールです。

第4正規化されていない例

例えば以下の表は「社員が持つ資格」と「社員が参加するプロジェクト」を1つにまとめた表です。

社員ID 社員名 資格 プロジェクト
1 佐藤 基本情報 会計システム
1 佐藤 基本情報 在庫管理
1 佐藤 応用情報 会計システム
1 佐藤 応用情報 在庫管理
2 鈴木 ネットワーク 会計システム

主キーが (社員ID, 資格, プロジェクト) となっていますが、実際には「資格」と「プロジェクト」は互いに独立しています。
つまり、社員ID に対して資格は複数持てるし、社員ID に対してプロジェクトも複数持てますが、資格とプロジェクトは独立しています。
そのため、現在のテーブルでは「資格 × プロジェクト」の組み合わせ分だけ行が増え、冗長なデータが生じています。
これが 多値従属による4NF違反となります。

第4正規化済みの例(4NF)

「社員の資格」と「社員のプロジェクト」を別のテーブルに分けます。

1. 社員テーブル

社員ID 社員名
1 佐藤
2 鈴木

2. 社員×資格テーブル

社員ID 資格
1 基本情報
1 応用情報
2 ネットワーク

3. 社員×プロジェクトテーブル

社員ID プロジェクト
1 会計システム
1 在庫管理
2 会計システム

これで「資格リスト」と「プロジェクトリスト」が分離され、冗長な「資格 × プロジェクトの掛け算表」、つまり多値従属 が解消され、4NF を満たします。

5. 第5正規形 (fifth normal form; 5NF)

以下の条件を満たすものが 第5正規形(5NF) となります。

  • 第4正規形(4NF) を満たしている
  • 不要な 結合従属 を排除する
  • テーブルを分割しても自然結合で元の情報を正しく復元できる状態にする

5.1. 第5正規化(5NF)とは

結合従属 を排除します。
4NFまでは「関数従属(1→1, 1→多, 多値従属)」を整理してきました
5NFでは「結合従属」、つまり 1つの大きな関係を分割したときに、不要なデータを生まずに再構成できるか を問題にします。
よくあるのは「三者関係(社員 × プロジェクト × 役割 など)」を正しく分割できていないケースです。

5.2. 第5正規化(5NF)の例

第5正規化されていない例

例えば次のように「社員・プロジェクト・役割」をまとめて管理している表があります。

社員ID プロジェクトID 役割
1 A 開発
1 A 設計
1 B 開発
2 A テスト

この表では「社員・プロジェクト・役割」の三者関係を直接保持しています。
しかし実際には、次の3つの二者関係が独立して存在していることが多いです。

  • 社員がどのプロジェクトに参加しているか
  • 社員がどんな役割を担えるか
  • プロジェクトで必要とされる役割は何か

この3つを正しく分解しないと、社員×役割×プロジェクト の掛け算で冗長データが増えたり、不要な組み合わせが入ったりする恐れがあります。

第5正規化済みの例(5NF)

三者関係を「二者関係の組み合わせ」に分解します。

1. 社員×プロジェクト

社員ID プロジェクトID
1 A
1 B
2 A

2. 社員×役割

社員ID 役割
1 開発
1 設計
2 テスト

3. プロジェクト×役割

プロジェクトID 役割
A 開発
A 設計
A テスト
B 開発

この3つを 自然結合(JOIN) すると、ちょうど最初の「社員×プロジェクト×役割」表が得られます。
余計な組み合わせは発生せず、冗長性も解消されるので、5NFを満たします。

6. ボイス・コッド正規形(Boyce-Codd Normal Form, BCNF)

ボイス・コッド正規形(Boyce-Codd Normal Form, BCNF) の定義は以下となります。

  • すべての関数従属において、左辺が候補キーである

つまり、非キー属性が主キーにのみ依存するだけでなく、候補キー以外に依存する関数従属がない状態です。
第3正規形(3NF)より少しだけ厳しい条件となります。

3NFとBCNFのどちらとも「関数従属性」をもとに正規化を行う考え方ですが、3NFはまだ一部の例外を許すのに対し、BCNFは例外を許さない点が違いです。

6.1. 定義の整理

  • 第3正規形 (3NF)
    「すべての非キー属性が主キーに完全従属」しており、かつ推移的従属がない状態です。
    ただし、決定項が候補キーの一部または候補キーに含まれる場合は例外的に許されます。

  • ボイス・コッド正規形 (BCNF)
    「すべての関数従属性 X → Y について、X が候補キーであること」を要求します。

6.2. 第3正規化されているが、ボイス・コッド正規形に違反している例

以下の表を見てみます。

  • 受講 ( 学生ID, 講義ID, 教員 )
学生ID 講義ID 教員
S1 C1 T1
S1 C2 T2
S2 C1 T1
S2 C2 T2

上記表で 関数従属性候補キー は以下の通りです。

  • 関数従属性

    • ① (学生ID, 講義ID) → 教員
      (学生がどの講義を受けるかで教員が決まる)
    • ② 教員 → 講義ID
      (教員は1つの講義しか担当しない)
       
  • 候補キー

    • 主キーは (学生ID, 講義ID)
       

第3正規形(3NF) かどうかチェックしてみます。

  • ① (学生ID, 講義ID) → 教員
    • 左辺が候補キーなのでOK
  • ② 教員 → 講義ID
    • 左辺の「教員」は候補キーではない。しかし「講義ID」は候補キーの一部を決定する属性。

したがって、上記表は第3正規形(3NF) を満たします。

次に、ボイス・コッド正規形 (BCNF) かどうかチェックしてみます。

  • ② 教員 → 講義ID
    • 左辺「教員」が候補キーではない

したがって、上記表は**ボイス・コッド正規形 (BCNF) ** に違反しています。

6.3. ボイス・コッド正規化済みの例(BCNF)

ボイス・コッド正規系(BCNF) にするには、次のように分解する必要があります。

1. 講義( 講義ID, 教員 )
(教員が担当する講義を管理)

講義ID 教員
C1 T1
C2 T2

2. 受講( 学生ID, 講義ID )
(学生がどの講義を受けているかを管理)

学生ID 講義ID
S1 C1
S1 C2
S2 C1
S2 C2

6.4. 第3正規系(3NF)とボイス・コッド正規形(BCNF)の違いのまとめ

第3正規系(3NF)とボイス・コッド正規形(BCNF)の違いを端的に書くと以下の通りです。

  • 3NF: 例外的に「候補キーに部分的に関わる属性」なら決定項になってよい
  • BCNF: 決定項は必ず「候補キー」でなければならない

7. 用語

7.1. 関数従属

属性集合 X が決まれば属性集合 Y が一意に決まるとき、X → Y が成り立つといい、これを 関数従属 といいます。

7.2. 部分関数従属

主キーが複合キーのとき、主キーの一部だけで非キー属性が決まってしまう従属を 部分関数従属 といいます。

7.3. 推移的関数従属

X → YY → Z が成り立ち、かつ Y が候補キーでないとき、X → Z推移的関数従属 といいます。

7.4. 多値従属

多値従属X →→ Y で表します。
X →→ Y が成り立つとは、X が決まると Y の集合が一意に決まる(ただし Y が他の属性と独立に繰り返される)場合です。

7.5. 結合従属

ある表 R が複数の射影に分解され、それを自然結合すると R に戻るとき、その属性分解の関係を結合従属といいます。

7.5. 候補キー

レコードを一意に特定できる最小の属性(または組)のことを 候補キー といいます。

7.6. 主キー

候補キーの中から選ばれた1つを 主キー といいます。

7.7. 非キー属性

候補キーに含まれない属性を 非キー属性 といいます。

8. まとめ

正規形 ポイント 補足
1NF セルは原子値(1セル1値) 繰り返しや複数値を持たない
2NF 複合キーの部分従属を排除 単一キーのみのテーブルでは自動的に満たされる
3NF 推移的関数従属を排除 非キー属性が他の非キー属性に依存してはいけない
BCNF すべての関数従属が候補キーによるものになるように整理 3NFでは許される特殊ケースを排除
4NF 多値従属を排除 1つのキーに対して独立した複数の繰り返し属性を分割
5NF 不要な結合従属を排除 分割しても自然結合で元の情報を完全に復元できる

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?