データベースの正規化

2022/08/31

データ

データベースの正規化とは

データの更新効率を低下させるデータの重複(冗長性)や更新処理のタイムラグなどで生じるデータの不整合(非一貫性)といった問題を解決するために、データテーブルを整理、分割すること。第一正規化から第五正規化まである。

正規化を進めていくとテーブル数が増えるため、情報を取り出す際にテーブル結合が必要になり、パフォーマンスが低下する。原則、第3正規化まで実施するが、パフォーマンス改善のためにあえて非正規化することもある。

非正規系

次のような非正規系の表を考える。

■ 社員テーブル

会社コード(pk)社員コード(pk)会社名社員名年齢部署コード部署名
c001e001A社赤井25d001人事
同上e002同上佐藤33d002営業
同上e003同上伊藤49d003開発
c002e001B社中村38d002営業
同上e002同上山田39d004経理

第一正規化

第一正規化では、一つのセルに一つの値しか含まない状態(第一正規形)にテーブルを変形する。

■ 社員テーブル

会社コード(pk)社員コード(pk)会社名社員名年齢部署コード部署名
c001e001A社赤井25d001人事
c001e002A社佐藤33d002営業
c001e003A社伊藤49d003開発
c002e001B社中村38d002営業
c002e002B社山田39d004経理

第二正規化

第二正規化では、部分関数従属性を解消するようにテーブルを分割する。部分関数従属とは、複合主キーの一部によって他の項目が一意に定まること。

社員テーブルでは、「会社名」以外は複合主キー({会社コード, 社員コード})に従属しているが、「会社名」は「会社コード」のみに従属している。そこで、この部分関数従属性を解消するため、次のようにテーブルを分割する。

■社員テーブル

会社コード(pk)社員コード(pk)社員名年齢部署コード部署名
c001e001赤井25d001人事
c001e002佐藤33d002営業
c001e003伊藤49d003開発
c002e001中村38d002営業
c002e002山田39d004経理

■会社テーブル

会社コード(pk)会社名
c001A社
c002B社

これによって、社員情報が不明の会社もテーブルに追加できるようになる。

■会社テーブル(社員情報が不明の会社を追加)

会社コード(pk)会社名
c001A社
c002B社
c003C社

第三正規化

第三正規化では、推移的関数従属性を解消するようにテーブルを分割する。推移的関数従属とは、段階的な関数従属があること。

社員テーブルでは、「部署名」は「部署コード」に従属していて、「部署コード」は「社員コード」に従属している。つまり、全体としては次のような推移的関数従属がある。

{社員コード} → {部署コード} → {部署名}

そこで、この推移的関数従属性を解消するため、次のようにテーブルを分割する。

■社員テーブル

会社コード(pk)社員コード(pk)社員名年齢部署コード
c001e001赤井25d001
c001e002佐藤33d002
c001e003伊藤49d003
c002e001中村38d002
c002e002山田39d004

■会社テーブル

会社コード(pk)会社名
c001A社
c002B社
c003C社

■部署

部署コード(pk)部署名
d001人事
d002営業
d003開発
d004経理

これによって、社員情報が不明の部署もテーブルに追加できるようになる。

■部署(社員情報が不明の部署を追加)

部署コード(pk)部署名
d001人事
d002営業
d003開発
d004経理
d005製造

ボイスコッド正規化

ボイスコッド正規化では、自明でない関数従属性を解消するようにテーブルを分割する。ボイスコット正規形は3.5正規形と呼ばれることもある。

例として、次のようなテーブルを考える。

■社員-チーム-チーム補佐

社員コード(pk)チームコード(pk)チーム補佐コード
e001t001a001
e002t001a002
e003t001a001
e004t002a003
e005t002a003

ここでは、「チーム補佐は同じチームに複数いることもあるが、一人が複数のチームを兼任することはできない」という業務ルールが存在すると仮定する。つまり、「チームコード」は「チーム補佐コード」に従属している。

{チーム補佐コード} → {チームコード}

このテーブルは、部分関数従属や推移的関数従属がないため第三正規形ではあるが、「非キーからキーへの関数従属」があるためボイスコッド正規形ではない。そこで、この「非キーからキーへの関数従属」を解消するため、次のようにテーブルを分割する。この分解は可逆的な分解になるように注意する。

■社員-チーム

社員コード(pk)チーム補佐コード(pk)
e001a001
e002a002
e003a001
e004a003
e005a003

■チーム補佐-チーム

チーム補佐コード(pk)チームコード
a001t001
a002t001
a003t002

第四正規化

第四正規化では、複数の多値従属性を解消するようにテーブルを分割する。多値従属とはキーに対して値の集合が対応があること。

例として、次のようなテーブルを考える。

■社員-チーム-製品

社員コード(pk)チームコード(pk)製品コード(pk)
e001t001P1
e001t001P2
e002t001P1
e002t002P1
e003t002P2

「社員コード」から「チームコード」と「製品コード」に多値従属性がある。

{社員コード} → {チームコード}
{社員コード} → {製品コード}

そこで、この複数の多値従属性を解消するため、次のようにテーブルを分割する。

■社員-チーム

社員コード(pk)チームコード(pk)
e001t001
e002t001
e002t002
e003t002

■社員-製品

社員コード(pk)製品コード(pk)
e001P1
e001P2
e002P1
e003P2

第五正規化

第五正規化では、結合従属性を解消するようにテーブルを分割する。

前述の「社員-チーム-製品」テーブルに、「社員コード」から「チームコード」と「製品コード」に多値従属性に加え、「チームコード」から「製品コード」に多値従属性がある場合を考える。

{社員コード} → {チームコード}
{社員コード} → {製品コード}
{チームコード} → {製品コード}

この場合、次のようにテーブルを分割する。

■社員-チーム

社員コード(pk)チームコード(pk)
e001t001
e002t001
e002t002
e003t002

■社員-製品

社員コード(pk)製品コード(pk)
e001P1
e001P2
e002P1
e003P2

■チーム-製品

チームコード(pk)製品コード(pk)
t001P1
t001P2
t001P1
t002P1
t002P2

参考資料

  • 達人に学ぶDB設計徹底指南書, ミック

  • 著者画像

    ゆうき

    2018/04からITエンジニアとして活動、2021/11から独立。主な使用言語はPython, TypeScript, SAS, etc.