リビン・テクノロジーズの開発部では、希望者に対してデータベーススペシャリスト試験に向けた講座を開催しています。今回その講師を務めたのですが、先日の講義で、ボイス・コッド正規形の説明に難儀したので、あらためて解説を行いたいと思います。
定義
まずは、ボイス・コッド正規形の定義から。
ボイス・コッド正規形は以下のように定義されています。
【定義】ボイス・コッド正規形
リレーション $R$ がボイス・コッド正規形であるとは、$X \rightarrow Y$ を $R$ の関数従属性とするとき、次のいずれかが成立するときをいう。
- $X \rightarrow Y$ は自明な関数従属性である。
- $X$ は $R$ のスーパーキーである。
いきなりこの定義を見て理解するのは難しいと思います。順に解説していきます。
各キーワードの解説
まず、定義に出てくる単語が難解なので、キーワードのそれぞれの意味を確認していきます。
関数従属性
関数従属性は、関係スキーマ(テーブル)内の属性(列)間の論理的な制約を表します。ある属性集合 $X$ の値が決まると、別の属性 $A$ の値が一意に決まる場合、「 $A$ は $X$ に関数従属する」といい、$X \rightarrow A$ と表記します。このとき $X$ を決定子、$A$ を被決定子と呼びます。
例 : (学籍番号) $\rightarrow$ (氏名)
この場合、学籍番号 が決まれば、氏名 は一意に決まります。
自明な関数従属性
自明な関数従属性とは、関数従属性 $X \rightarrow A$ において、 $A$ が $X$ に含まれている場合のことです。これは、論理的に必ず成立するため、データベースの設計において特に意味を持たない「自明」な制約と見なされます。
例 : (学籍番号, 受講講座番号) $\rightarrow$ (学籍番号)
学籍番号 と 受講講座番号 が決まれば、そこに含まれる 学籍番号 は必ず決まります。これは必ず成り立ち、自明です。
スーパーキー
スーパーキーは、関係スキーマの タプル(行)を一意に識別できる属性または属性の集合 です。テーブルのすべての行が、そのキーの値によって区別できることを意味します。
例 : (学籍番号)、(学籍番号, 氏名)
学籍番号 は学生を一意に特定できるのでスーパーキーです。また、(学籍番号, 氏名) も学生を一意に特定できるのでスーパーキーになります。スーパーキーは候補キーの上位集合であり、余分な属性を含んでいても構いません。
候補キー
候補キーは、スーパーキーのうち、極小なもの(最小限の属性で構成されているもの)です。つまり、候補キーからどの属性を一つでも削除すると、スーパーキーではなくなってしまうような属性の集合です。
すべての候補キーはスーパーキーですが、すべてのスーパーキーが候補キーとは限りません。
例 : 学籍番号、メールアドレス
もし学生にそれぞれ一意のメールアドレスが割り当てられているなら、学籍番号とメールアドレスはいずれも候補キーになり得ます。
これとは別に 主キー という単語もあります。これは候補キーの中から、データベース設計者がメインとなるキーを一つ選択したものです。
正規化のステップ : 2NF と 3NF
ボイス・コッド正規形に至るには、第2正規形、第3正規形と順に正規化していきます。
これらの正規化は以下のように、関数従属性を排除することで進めます。
第2正規形 (2NF) と部分関数従属性
部分関数従属性 とは、候補キーの一部に他の非キー属性が関数従属している状態を指します。第2正規形 (2NF) は、この部分関数従属性を排除することを目的としています。
例 : (学籍番号, 受講講座番号) $\rightarrow$ (講座名)
- このテーブルの候補キーは (学籍番号, 受講講座番号) です。
- 講座名 は候補キー全体でなく、その一部である 受講講座番号 だけで一意に決まります。
- この状態は部分関数従属性であり、2NF の違反です。
- 正規化 : テーブルを (学籍番号, 受講講座番号) と (講座番号, 講座名) に分割します。
第3正規形 (3NF) と推移的関数従属性
推移的関数従属性 とは、ある非キー属性が、候補キーではなく別の非キー属性に関数従属している状態を指します。第3正規形(3NF)は、この推移的関数従属性を排除することを目的としています。
例 : (学籍番号) $\rightarrow$ (学科名) $\rightarrow$ (学科長)
- このテーブルの候補キーは 学籍番号 です。
- 学科長 は候補キーである 学籍番号 に直接関数従属しているのではなく、非キー属性である 学科名 を介して間接的に従属しています。
- この状態は推移的関数従属性であり、3NFの違反です。
- 正規化:テーブルを (学籍番号, 学科名) と (学科名, 学科長) に分割します。
ボイス・コッド正規形 (BCNF)
第2正規形 (2NF) で解消する部分関数従属性や、第3正規形 (3NF) で解消する推移的関数従属性ではないが、「自明でない関数従属性」かつ「決定子がスーパーキーでない関数従属性」という特殊なケースが存在します。この特殊なケースがボイス・コッド正規形 (BCNF) の正規化の対象となります。
例 : 学生-科目-担当教員
学生 | 科目 | 担当教員 |
---|---|---|
山田 太郎 | 数学 | 二本松 晋 |
山田 太郎 | 英語 | 安河内 鉄三 |
清水 花子 | 数学 | 二本松 晋 |
清水 花子 | 物理 | 朝永 振次郎 |
この例では、1人の担当教員が1つの科目しか担当しないという制約があると仮定します。
このテーブルには、以下の関数従属性があります。
-
(学生, 科目) $\rightarrow$ 担当教員
学生と科目の組み合わせが一意に決まれば、担当教員も一意に決まります。 -
担当教員 $\rightarrow$ 科目
一人の教員は一つの科目しか担当しないという前提です。
まず、このテーブルの候補キーを特定します。テーブル全体を一意に識別できる属性の組み合わせは、(学生, 科目) です。(学生, 科目) が分かれば、担当教員は一意に決まります。そのため、候補キーは (学生, 科目) です。
二つの関数従属性について、BCNF の定義に照らし合わせてみます。
- (学生, 科目) $\rightarrow$ 担当教員
- この関数従属性の決定子は、 (学生, 科目) です。
- (学生, 科目) は候補キーなので、スーパーキーでもあります。
- この関数従属性は BCNF の定義を満たしています。
- 担当教員 $\rightarrow$ 科目
- この関数従属性の決定子は、 担当教員 です。
- しかし 担当教員 は、テーブル全体を一意に識別できません。したがって 担当教員 は、スーパーキーではありません。
- 担当教員 がスーパーキーでないにもかかわらず、担当教員 $\rightarrow$ 科目 という関数従属性が存在しているため、このテーブルは BCNF に違反しています。
このテーブルが、ボイス・コッド正規形になるよう、以下のように分解します。
テーブル1 : 学生-担当教員
学生 | 担当教員 |
---|---|
山田 太郎 | 二本松 晋 |
山田 太郎 | 安河内 鉄三 |
清水 花子 | 二本松 晋 |
清水 花子 | 朝永 振次郎 |
※ 1人の学生が複数の科目を履修し、それぞれ別の担当教員がいるため、学生-担当教員 テーブルには一人の学生に対し複数の行が存在します。
テーブル2 : 担当教員-科目
担当教員 | 科目 |
---|---|
二本松 晋 | 数学 |
安河内 鉄三 | 英語 |
朝永 振次郎 | 物理 |
このように分解することで、それぞれのテーブルは BCNF となります。
この分解により、例えば「二本松 晋」の担当科目を変更する」という場合に、学生-科目-担当教員 テーブルでは複数のレコードを更新する必要がありましたが、担当教員-科目 テーブルでは1つのレコードを更新するだけで済みます。これにより更新異常が解消されます。
まとめ
ボイス・コッド正規形は、第2正規形 (2NF)、第3正規形 (3NF) では解決できない、特殊な関数従属性を排除することを目的とした、より厳格な正規形です。
今回の BCNF の違反例では、「担当教員」という 非キー属性 から、候補キーの一部(キー属性) である「科目」への関数従属性が BCNF 違反の原因でした。このように、決定子がスーパーキーではない関数従属性を解消することで、データの更新、挿入、削除の際に発生する更新異常を防ぎ、データベースの整合性を高めることができます。
実務では、すべてのテーブルが常にBCNFであるとは限りませんが、BCNFの考え方を理解しておくことで、正規化による設計上の判断力が高まります。
本記事が、ボイス・コッド正規形の理解の一助になれば幸いです。