はじめに
データベースを正規化することで、データの冗長や更新異常を減らし、整合性を高められます。ここでは、各正規形とキー、関数従属性などの関連知識を再整理し、まとめていきます。
本文
第1正規形(1NF)
定義: テーブルのすべての列が単一の値を持ち、繰り返し要素がない状態
1NFを満たしていない場合、1つのセルにリストやカンマ区切りの値が入るなど、属性が「複数値」を持つことがあります。1NF化によって、データは最も細かい単位に分解され、SQLによる検索や集計が容易になります。また、1NFは他の正規形への出発点です。1NFを適切に満たすことで、以降の正規化(2NF、3NFなど)をスムーズに進めることができます。
【1NF化例(電話番号分離)】
非1NF
顧客ID | 電話 |
---|---|
1 | 03-XXXX,090-YYYY |
1NF
顧客ID | 電話 |
---|---|
1 | 03-XXXX |
1 | 090-YYYY |
候補キー(Candidate Key)とスーパーキー
スーパーキーは行を一意識別できる属性または属性の組みのことですが、冗長な属性を含む場合があります。そこから余分な属性を取り除いた極小のものが候補キーです。候補キーが明確であれば、主キー選定や外部キー設定もしやすく、データベース全体の整合性維持に有利です。
極小とは、「もう1つ属性が欠落すると条件を満たさなくなる」ギリギリの属性または属性の組です。
主キー(Primary Key)、代理キー(Alternate Key)、複合キー
主キーは候補キーから1つ選んだ特別なキーで、行を一意に識別しNULLを許しません。代理キーは主キー以外の候補キーを指します。複合キーは主キー、外部キーが複数属性からなるキーで、扱いにくい場合は代替として連番などの1つの属性で一意となるキー(ID列など)を用いることが多いです。主キーの適切な選定は、更新異常の防止や検索性能、管理コストに大きく影響します。
第2正規形(2NF)
定義: 1NFを満たし、非キー属性が主キーの一部にのみ依存する部分関数従属を排除した状態
2NFは、主キーが複合キーの場合に特に重要です。たとえば、{伝票ID, 商品ID}
が主キーの場合、顧客IDと顧客名が伝票IDだけで決まるなら部分関数従属が発生します。{伝票ID} → {顧客ID, 顧客名}
を別テーブルに切り出すことで、更新異常を防止し、整合性を高めます。2NFは「非キー属性の候補キーへの完全関数従属」を保証し、データの一貫性を強化します。
【2NF化例(部分関数従属排除)】
非2NF
伝票(伝票ID, 顧客ID, 顧客名, 商品ID, 商品名, 数量)
伝票ID | 顧客ID | 顧客名 | 商品ID | 商品名 | 数量 |
---|---|---|---|---|---|
101 | A10 | C001 | A001 | WidgetA | 1 |
101 | A10 | C001 | B002 | WidgetB | 2 |
102 | A11 | C002 | B001 | WidgetA | 3 |
102 | A11 | C002 | B003 | WidgetC | 1 |
102 | A11 | C002 | B004 | WidgetD | 4 |
103 | A12 | C003 | B004 | WidgetD | 5 |
104 | A12 | C003 | B005 | WidgetE | 5 |
2NF
伝票明細(伝票ID, 商品ID, 商品名, 数量)
伝票ID | 商品ID | 商品名 | 数量 |
---|---|---|---|
101 | A001 | WidgetA | 1 |
101 | B002 | WidgetB | 2 |
102 | B001 | WidgetA | 3 |
102 | B003 | WidgetC | 1 |
102 | B004 | WidgetD | 4 |
103 | B004 | WidgetD | 5 |
104 | B005 | WidgetE | 5 |
伝票(伝票ID, 顧客ID, 顧客名)
伝票ID | 顧客ID | 顧客名 |
---|---|---|
101 | A10 | C001 |
101 | A10 | C001 |
102 | A11 | C002 |
102 | A11 | C002 |
102 | A11 | C002 |
103 | A12 | C003 |
104 | A12 | C003 |
第3正規形(3NF)
定義: 2NFを満たし、推移的関数従属を排除した状態
3NFは非キー属性同士の依存を排除します。例えば、{伝票番号} → {顧客番号}
、{顧客番号} → {顧客名}
という依存があるなら、顧客名は伝票番号を経由して決まる推移的関数従属です。顧客番号と顧客名を別テーブルに分割し、伝票テーブルには顧客番号のみ保持することで更新異常を防げます。3NFまで行うと、多くのケースで十分な正規化となります。
【3NF化例(推移的関数従属排除)】
非3NF
伝票(伝票番号, 顧客番号, 顧客名)
伝票番号 | 顧客番号 | 顧客名 |
---|---|---|
S001 | A10 | C001 |
S002 | A11 | C002 |
S003 | A12 | C003 |
S004 | A12 | C003 |
3NF
伝票(伝票番号, 顧客番号)
伝票番号 | 顧客番号 |
---|---|
S001 | A10 |
S002 | A11 |
S003 | A12 |
S004 | A12 |
顧客(顧客番号, 顧客名)
顧客番号 | 顧客名 |
---|---|
A10 | C001 |
A11 | C002 |
A12 | C003 |
外部キー(Foreign Key)
外部キーは、ある関係が他の関係の主キー(または候補キー)を参照することで、整合性を確保します。これにより、存在しないキーを参照する不正データの挿入を防ぎ、データ間の一貫性を保証します。正規化によって関係を分割しても、外部キーを用いて参照制約を維持すれば、データの意味的なつながりを保ち、整合性を強化できます。
ボイス・コッド正規形(BCNF)
定義: 3NFをさらに厳しくし、すべての関数従属性X→Y
でXが必ず候補キーである状態
BCNFは3NFより厳格で、非キー属性同士だけでなく、キー属性間の微妙な依存関係も排除します。たとえば、関係R{学生名, 科目名, 教員名} に {学生名, 科目名} → {教員名}
と {教員名} → {科目名}
が成立するとします。{学生名, 科目名, 教員名}
はすべて候補キーなので理論的には3NFを満たします。ですが、{教員名} → {科目名}
は {学生名, 科目名}
に対する部分関数従属性です。{教員名} → {科目名}
は自明な関数従属性ではなく、{教員名}
は関係Rのスーパーキーではないので、分解できます。
一方で、関係Rに存在した {学生名, 科目名} → {教員名}
という関数従属性は、分解後の2つのテーブルだけでは直接表現できなくなります。これは「関数従属性損失」と呼ばれる現象で、BCNF化によって特定の関数従属性が関係分解前の形で保持されない問題です。関数従属性損失が起きると、元の依存関係を維持するために追加の結合操作やアプリケーションロジックで補完する必要が生じます。情報無損失分解かつ関数従属性保存で問題なく分解出るのは3NFまでです。
【BCNF化例】
非BCNF
関係"学生名, 教員名, 科目名"
学生名 | 教員名 | 科目名 |
---|---|---|
S001 | T010 | 数学 |
S001 | T020 | 国語 |
S003 | T030 | 英語 |
BCNF
学生-教員(学生名, 教員名)
学生名 | 教員名 |
---|---|
S001 | T010 |
S001 | T020 |
S003 | T030 |
教員-科目(教員名, 科目名)
教員名 | 科目名 |
---|---|
T010 | 数学 |
T020 | 国語 |
T030 | 英語 |
第4正規形(4NF)
定義: BCNFを満たした上で、多値従属性を排除した状態
多値従属性X->->Y
とは、Xが決まるとYが独立した属性群として決定される状況です。たとえば、あるアーティストが複数の楽曲と複数のファンクラブ地域を持つ場合、アーティスト→→楽曲
、アーティスト→→地域
となり、それぞれ独立した繰り返し要素が存在します。4NF化では、これらを独立テーブルに分け、冗長性を排除します。
【4NF化例】
非4NF
アーティスト(アーティストID, 楽曲, ファンクラブ地域)
アーティストID | 曲名 | ファンクラブ地域 |
---|---|---|
A900 | SongX | 関東 |
A900 | SongX | 関西 |
A900 | SongY | 関東 |
A900 | SongY | 関西 |
4NF
アーティスト-楽曲(アーティストID, 楽曲)
アーティストID | 曲名 |
---|---|
A900 | SongX |
A900 | SongY |
アーティスト-地域(アーティストID, ファンクラブ地域)
アーティストID | ファンクラブ地域 |
---|---|
A900 | 関東 |
A900 | 関西 |
第5正規形(5NF)
定義: 4NFを満たし、結合従属性(Join Dependency)を分解して、自然結合で元の関係に戻せる状態。
5NFは、3つ以上の関係に分解しても情報損失がなく再結合可能な状態を求めます。これは非常に特殊なケースで、データが複雑な組み合わせ依存を持つ場合に必要です。5NFまで正規化すると冗長性は最小化されますが、実務上ここまで求めることはまれで、要件やコスト、性能を総合的に判断して適用します。
【例(5NF)】
非5NF
サプライヤー(仕入先ID, 部品ID, プロジェクトID)
仕入先ID | 部品ID | プロジェクトID |
---|---|---|
S10 | P01 | PRJ100 |
S10 | P02 | PRJ100 |
S10 | P01 | PRJ200 |
5NF
仕入先-部品(仕入先ID, 部品ID)
仕入先ID | 部品ID |
---|---|
S10 | P01 |
S10 | P02 |
部品-プロジェクト(部品ID, プロジェクトID)
部品ID | プロジェクトID |
---|---|
P01 | PRJ100 |
P01 | PRJ200 |
P02 | PRJ100 |
仕入先-プロジェクト(仕入先ID, プロジェクトID)
仕入先ID | プロジェクトID |
---|---|
S10 | PRJ100 |
S10 | PRJ200 |
まとめ
正規化は、1NFからスタートして2NF、3NF、BCNF、4NF、5NFと進むにつれ、少しずつデータの冗長性や更新時の問題を解消し、より整合性の高いデータベースを構築するための手法です。実務では3NFまでで十分な場合が多いものの、システムの要件や扱うデータの特性によっては、さらに高次の正規形の適用を検討することもあります。
正規化を理解するうえで欠かせない、候補キー・主キー・外部キーといったキーの概念や、関数従属性、多値従属性、結合従属性などの基本的な考え方は、信頼性の高いデータベース設計を支える基盤です。これらをしっかりと押さえておきましょう!明日は関係演算です!