データベースの正規化~第1正規形から第5正規形まで
2025/03/19
データ正規化とは
データベース設計において、データの重複をなくし、一貫性と整合性を保ちながら効率的に情報を管理できるように、テーブルを整理・分割することを正規化と呼ぶ。正規化により、同じ情報が複数の場所に保存されることを防ぎ、情報を変更する際には1箇所だけデータを更新すれば良くなるため、更新漏れや不整合の発生を予防できる。
正規化には、第1正規形から第5正規形までの段階があり、段階が進むごとにテーブルは細分化されていく。各段階の正規化では、正規化前の状態に戻せるようにテーブルを分解する(無損失分解)。データベースが高度に正規化されている場合、求める情報を得るために多くのテーブルを結合する必要があり、パフォーマンスに影響を与えることもある。そのため、実務では原則として第3正規形までの正規化が推奨されるが、場合によってはパフォーマンス向上のためにあえて非正規化することもある。
以下、具体例をもとに各正規化について解説する。
非正規形
まずは、正規化を行う前の非正規形の例を示す。以下、この表をもとに正規化していく。
領収書ID | 購入時間 | 購入店舗 | 商品名 | 顧客ID | 顧客名 | サイズ | カラー | キャンペーン | 単価 | 個数 | 購入価格 | 責任者 |
R001 | 2023/04/10 09:00 | 店舗A | Tシャツ | C001 | 山田太郎 | M | 赤 | 学生向けキャンペーン | 2500 | 2 | 5000 | 田中一郎 |
ジーンズ | L | 青 | 学生向けキャンペーン | 6000 | 1 | 6000 | ||||||
R002 | 2023/04/11 14:30 | 店舗B | ワンピース | C002 | 佐藤花子 | S | 緑 | 新春キャンペーン | 9000 | 1 | 9000 | 山本花子 |
R003 | 2023/04/14 10:00 | 店舗A | Tシャツ | C003 | 高橋三郎 | M | 白 | 在庫一掃キャンペーン | 2600 | 1 | 2600 | 鈴木太郎 |
R004 | 2023/04/15 11:00 | 店舗A | Tシャツ | C004 | 伊藤四郎 | S | 青 | 学生向けキャンペーン | 2500 | 1 | 2500 | 佐藤次郎 |
第1正規形
第1正規形は一つのセルに一つの値のみを持っている状態。上述の非正規形を第1正規形に正規化したものを以下に示す。
領収書ID (pk) | 購入時間 (pk) | 購入店舗 (pk) | 商品名 (pk) | 顧客ID | 顧客名 | サイズ | カラー | キャンペーン | 単価 | 個数 | 購入価格 | 責任者 |
R001 | 2023/04/10 09:00 | 店舗A | Tシャツ | C001 | 山田太郎 | M | 赤 | 学生向けキャンペーン | 2500 | 2 | 5000 | 田中一郎 |
R001 | 2023/04/10 09:00 | 店舗A | ジーンズ | C001 | 山田太郎 | L | 青 | 学生向けキャンペーン | 6000 | 1 | 6000 | 田中一郎 |
R002 | 2023/04/11 14:30 | 店舗B | ワンピース | C002 | 佐藤花子 | S | 緑 | 新春キャンペーン | 9000 | 1 | 9000 | 山本花子 |
R003 | 2023/04/14 10:00 | 店舗A | Tシャツ | C003 | 高橋三郎 | M | 白 | 在庫一掃キャンペーン | 2600 | 1 | 2600 | 鈴木太郎 |
R004 | 2023/04/15 11:00 | 店舗A | Tシャツ | C004 | 伊藤四郎 | S | 青 | 学生向けキャンペーン | 2500 | 1 | 2500 | 佐藤次郎 |
※ pk(primary key:主キー)はレコードを一意に識別するために利用するためのカラムのこと。上の例では{領収書ID, 購入時間, 購入店舗, 商品名}の組(複合主キー)が決まれば、どのレコードを指しているか特定できる。
第2正規形
第2正規形は、第1正規形の条件に加えて、部分関数従属を排除した状態。部分関数従属とは、複合主キーの一部によって他の項目が一意に定まること。
上述の第1正規形では、「顧客ID」、「顧客名」、「責任者」は、複合主キー({領収書ID, 購入時間, 購入店舗, 商品名}の組)ではなく、複合主キーの一部({領収書ID, 購入時間, 購入店舗}の組)によって一意に定まる。つまり、次のような部分関数従属がある。
{領収書ID, 購入時間, 購入店舗} → {顧客ID}
{領収書ID, 購入時間, 購入店舗} → {顧客名}
{領収書ID, 購入時間, 購入店舗} → {責任者}
※ A → Bは、BがAに関数従属していることを表し、Aが決まるとBが決まる。
そこで、この部分関数従属を排除するため、次のように分割する。
(1) 購入マスタ
領収書ID (pk) | 購入時間 (pk) | 購入店舗 (pk) | 顧客ID | 顧客名 | 責任者 |
R001 | 2023/04/10 09:00 | 店舗A | C001 | 山田太郎 | 田中一郎 |
R002 | 2023/04/11 14:30 | 店舗B | C002 | 佐藤花子 | 山本花子 |
R003 | 2023/04/14 10:00 | 店舗A | C003 | 高橋三郎 | 鈴木太郎 |
R004 | 2023/04/15 11:00 | 店舗A | C004 | 伊藤四郎 | 佐藤次郎 |
(2) 購入詳細
領収書ID (pk) | 購入時間 (pk) | 購入店舗 (pk) | 商品名 (pk) | キャンペーン | サイズ | カラー | 単価 | 個数 | 購入価格 |
R001 | 2023/04/10 09:00 | 店舗A | Tシャツ | 学生向けキャンペーン | M | 赤 | 2500 | 2 | 5000 |
R001 | 2023/04/10 09:00 | 店舗A | ジーンズ | 学生向けキャンペーン | L | 青 | 6000 | 1 | 6000 |
R002 | 2023/04/11 14:30 | 店舗B | ワンピース | 新春キャンペーン | S | 緑 | 9000 | 1 | 9000 |
R003 | 2023/04/14 10:00 | 店舗A | Tシャツ | 在庫一掃キャンペーン | M | 白 | 2600 | 1 | 2600 |
R004 | 2023/04/15 11:00 | 店舗A | Tシャツ | 学生向けキャンペーン | S | 青 | 2500 | 1 | 2500 |
第3正規形
第3正規形は、第2正規形の条件に加えて、推移的関数従属を排除した状態。推移的関数従属とは、二段階以上の従属関係があること。
上述の第2正規形の購入マスタでは、「顧客名」は「顧客ID」に従属していて、「顧客ID」は複合主キーに従属している。つまり、次のような推移的関数従属がある。
{領収書ID, 購入時間, 購入店舗} → {顧客ID} → {顧客名}
※ A → Bは、BがAに関数従属していることを表し、Aが決まるとBが決まる。
そこで、この推移的関数従属を排除するため、購入マスタを次のように分割する。
(1) 顧客マスタ
顧客ID (pk) | 顧客名 |
C001 | 山田太郎 |
C002 | 佐藤花子 |
C003 | 高橋三郎 |
C004 | 伊藤四郎 |
(2) 購入マスタ(更新版)
領収書ID (pk) | 購入時間 (pk) | 購入店舗 (pk) | 顧客ID | 責任者 |
R001 | 2023/04/10 09:00 | 店舗A | C001 | 田中一郎 |
R002 | 2023/04/11 14:30 | 店舗B | C002 | 山本花子 |
R003 | 2023/04/14 10:00 | 店舗A | C003 | 鈴木太郎 |
R004 | 2023/04/15 11:00 | 店舗A | C004 | 佐藤次郎 |
ボイス・コッド正規形
ボイス・コッド正規形は、第3正規形よりさらに厳しく、テーブル内の非自明なすべての従属関係が、レコードを一意に識別できるキー(スーパーキー)への従属になっている状態。第3.5正規形と呼ばれることもある。
「責任者は複数の店舗を兼任できない」というルールが存在すると仮定する。つまり、上述の第3正規形の購入マスタでは、「購入店舗」は「責任者」(非キー)に従属していることになる。
{責任者} → {購入店舗}
※ A → Bは、BがAに関数従属していることを表し、Aが決まるとBが決まる。
そこで、この非キーへの関数従属を排除するため、購入マスタを次のように分割する。
(1) 購入マスタ(更新版)
領収書ID (pk) | 購入時間 (pk) | 顧客ID | 責任者 (pk) |
R001 | 2023/04/10 09:00 | C001 | 田中一郎 |
R002 | 2023/04/11 14:30 | C002 | 山本花子 |
R003 | 2023/04/14 10:00 | C003 | 鈴木太郎 |
R004 | 2023/04/15 11:00 | C004 | 佐藤次郎 |
(2) 責任者マスタ
責任者 (pk) | 購入店舗 |
田中一郎 | 店舗A |
山本花子 | 店舗B |
鈴木太郎 | 店舗A |
佐藤次郎 | 店舗A |
第4正規形
第4正規形は、ボイス・コッド正規形の条件に加えて、複数の多値従属を排除した状態。多値従属とはある項目が決まると他の項目の集合が決まること。
次に示す商品マスタにおいて、「商品名」が決まれば「サイズ」と「カラー」の集合が決まる。例えば、商品名がTシャツであれば、サイズはS/L/Mのいずれか、カラーは赤/青/白のいずれかであると決まる。このとき、「サイズ」と「カラー」はそれぞれ独立で決定する。
商品マスタ
商品名 (pk) | サイズ (pk) | カラー (pk) |
Tシャツ | S | 赤 |
Tシャツ | S | 青 |
Tシャツ | S | 白 |
Tシャツ | M | 赤 |
Tシャツ | M | 青 |
Tシャツ | M | 白 |
Tシャツ | L | 赤 |
Tシャツ | L | 青 |
Tシャツ | L | 白 |
ジーンズ | S | 青 |
ジーンズ | S | 黒 |
ジーンズ | M | 青 |
ジーンズ | M | 黒 |
ジーンズ | L | 青 |
ジーンズ | L | 黒 |
ジーンズ | XL | 青 |
ジーンズ | XL | 黒 |
ワンピース | S | 緑 |
ワンピース | S | 白 |
ワンピース | M | 緑 |
ワンピース | M | 白 |
ワンピース | L | 緑 |
ワンピース | L | 白 |
つまり、次のような2つの多値従属がある。
{商品名} →→ {サイズ}
{商品名} →→ {カラー}
※ A →→ Bは、BがAに多値従属していることを表し、Aが決まるとBの集合が決まる。
そこで、この2つの多値従属を排除するため、商品マスタを次のように分割する。
(1) 商品名_サイズ
商品名 (pk) | サイズ (pk) |
Tシャツ | S |
Tシャツ | M |
Tシャツ | L |
ジーンズ | S |
ジーンズ | M |
ジーンズ | L |
ジーンズ | XL |
ワンピース | S |
ワンピース | M |
ワンピース | L |
(2) 商品名_カラー
商品名 (pk) | カラー (pk) |
Tシャツ | 赤 |
Tシャツ | 青 |
Tシャツ | 白 |
ジーンズ | 青 |
ジーンズ | 黒 |
ワンピース | 緑 |
ワンピース | 白 |
第5正規形
第5正規形は、第4正規形の条件に加えて、結合従属を排除した状態。結合従属とは3つ以上に分解可能な従属性のこと。
「店舗ごとに取扱商品と実施されるキャンペーンは異なり、商品ごとに適用可能なキャンペーンも異なる」というルールが存在すると仮定する。そうすると、次に示すキャンペーンマスタにおいて、「購入店舗」が決まれば「商品名」と「キャンペーン」の集合が決まり、「商品名」が決まれば「キャンペーン」の集合が決まる。
キャンペーンマスタ
購入店舗 (pk) | 商品名 (pk) | キャンペーン (pk) |
店舗A | Tシャツ | 学生向けキャンペーン |
店舗A | Tシャツ | 在庫一掃キャンペーン |
店舗A | ジーンズ | 学生向けキャンペーン |
店舗B | Tシャツ | 新春キャンペーン |
店舗B | Tシャツ | 在庫一掃キャンペーン |
店舗B | ジーンズ | 新春キャンペーン |
店舗B | ワンピース | 新春キャンペーン |
つまり、次のような結合従属がある。
{購入店舗} ---> {商品名}
│ ↕
└ -----> {キャンペーン}
そこで、この結合従属を排除するため、キャンペーンマスタを次のように分割する。
(1) 購入店舗_商品名
購入店舗 (pk) | 商品名 (pk) |
店舗A | Tシャツ |
店舗A | ジーンズ |
店舗B | Tシャツ |
店舗B | ジーンズ |
店舗B | ワンピース |
(2) 購入店舗_キャンペーン
購入店舗 (pk) | キャンペーン (pk) |
店舗A | 学生向けキャンペーン |
店舗A | 在庫一掃キャンペーン |
店舗B | 新春キャンペーン |
店舗B | 在庫一掃キャンペーン |
(3) 商品名_キャンペーン
商品名 (pk) | キャンペーン (pk) |
Tシャツ | 学生向けキャンペーン |
Tシャツ | 新春キャンペーン |
Tシャツ | 在庫一掃キャンペーン |
ジーンズ | 学生向けキャンペーン |
ジーンズ | 新春キャンペーン |
ワンピース | 新春キャンペーン |