このページでは、部分関数従属や推移的関数従属などの関数従属と、第1〜第3正規化の手順、正規化で防げる更新時異常、非正規化がわかります。
- 一言で言うと:
- 表の中の重複をなくして、更新したときに矛盾が起きないように表を分ける話
- 分け方の手がかりは、「この列が決まればあの列が決まる」という関数従属
手がかり(関数従属:部分・完全・推移的)→ 分け方(第1正規化 → 第2正規化 → 第3正規化)→ 分けすぎたら戻す(非正規化)
覚え方の軸
- 正規化は「繰返し → 部分 → 推移」の順に取り除く
- 第1正規化は、繰返し部分をなくす(非正規形 → 第1正規形)
- 第2正規化は、主キーの一部に決まってしまう列(部分関数従属)を別の表に出す
- 第3正規化は、主キー以外の列に決まってしまう列(推移的関数従属)を別の表に出す
- 関数従属は「何が決まれば何が決まるか」
- x → y:
- xが決まればyが決まる(xが決定項、yが従属項)
- 部分関数従属は、複合キーの一部だけでyが決まる。完全関数従属は、キー全部がないとyが決まらない
- 推移的関数従属は、x → y → z と間接的に決まる
- x → y:
- 第2正規化がいるのは「主キーが複合キーのときだけ」
- 主キーが1つの属性なら、部分関数従属は起きないので、第1正規形ならすでに第2正規形
- 正規化しないと起きる更新時異常は3つ
- 修正時異常(何行も直す必要)、挿入時異常(登録できない)、削除時異常(消したくないものまで消える)
- 分けた表には、元の表の主キーを外部キーとして残す(結合で元に戻せるように)
関数従属:何が決まれば何が決まるか(★)
- 関数従属:
- ある属性xの値が決まると、他の属性yの値が一意に決まる関係
- 「x → y」と書く
- 独立属性(決定項):
- 「x → y」のx
- 従属属性(従属項):
- 「x → y」のy
- 関数従属が大事な理由:
- 1つの表の中の属性間にある関数従属に注目して整理(正規化)すると、整合性を保ちやすいデータベースを設計できる
- 関数従属の例え:
- 「郵便番号 → 町名」。郵便番号が決まれば町名が決まる。でも町名が決まっても郵便番号は1つに決まるとは限らない
- 多値従属:
- xに対して1つのyではなく、複数の値を持つ1つの集合が決まる従属関係
- 「x →→ y」と書く
- 例えば、「社員 →→ 資格」(1人の社員に、複数の資格の集合が決まる)
① 部分関数従属
- 部分関数従属:
- 「x → y」の関係で、yが、xの真部分集合にも関数従属するとき、yはxに部分関数従属するという
- 具体的には:
- 独立属性xがx1とx2の2つの属性でできている場合、{x1, x2} → y が成り立ち、かつ、x1 → y または x2 → y のどちらかが成り立つなら、{x1, x2}とyの間に部分関数従属がある
- 部分関数従属は、独立属性xが複数の属性でできている場合に起こりうる
- 真部分集合:
- 集合x1がxの部分集合で、かつ x1 = x ではないとき、x1はxの真部分集合という
- 自明な関数従属性:
- x1がxの部分集合なら、「x → x1」は必ず成り立つ。このような関数従属性
- 例えば、{売上番号, 商品番号} → 商品番号 は当たり前に成り立つ
② 完全関数従属
- 完全関数従属:
- 「x → y」の関係で、yが、xのどの真部分集合にも関数従属しないとき
- 単一の属性なら常に完全:
- 独立属性xが1つの属性でできている場合は、常に完全関数従属が成り立つ
完全関数従属と部分関数従属
- ①だけ成立:
- ① {x1, x2} → y だけが成り立つなら、完全関数従属
- ①と②が成立:
- ① {x1, x2} → y と ② x2 → y が両方成り立つなら、部分関数従属
③ 推移的関数従属
- 推移的関数従属:
- 直接ではなく、間接的に関数従属している関係
- 属性x、y、zで、「x → y」「y → z」「y →/ x」が成り立つとき、zはxに推移的関数従属しているという
- 「y →/ x」:
- xはyに関数従属しない(yが決まってもxは決まらない)という意味
- 完全推移的関数従属:
- さらに「z →/ y」が成り立てば、zはxに完全推移的関数従属しているという
- 注意:
- 属性x、y、zは、互いに重複しない
- 「y → x」が成り立つ場合:
- 「x ←→ y → z」となり、zはxとyに直接関数従属する(推移的ではない)
- 推移的関数従属の例え:
- 「生徒番号 → 担任の先生 → 先生の内線番号」。生徒番号から内線番号は、先生を通して間接的に決まる
各関数従属の例(★)
- 売上明細表(売上番号、商品番号、商品名、単価、数量):
- “商品名”と“単価”は、主キーの一部である“商品番号”だけで決まるので、主キーに部分関数従属
- “数量”は、{売上番号, 商品番号} が両方決まらないと決まらないので、主キーに完全関数従属
- 売上表(売上番号、日付、顧客番号、顧客名):
- 売上番号 → 顧客番号 → 顧客名 が成り立ち、顧客番号が決まっても売上番号は決まらない
- だから、“顧客名”は“顧客番号”を介して、主キー“売上番号”に推移的関数従属
推論律
- 推論律:
- 複数の関数従属から、1つの関数従属を導くための規則
- 推移律:
- A → B、B → C ならば、A → C
- 合併律:
- A → B、A → C ならば、A → BC
- 増加律:
- A → B ならば、AC → BC
- 反射律:
- BがAの部分集合ならば、A → B
- 擬推移律:
- A → B、BC → D ならば、AC → D
正規化の手順:繰返し → 部分 → 推移の順に分ける(★)
① 第1正規化
- 第1正規化:
- 関係データベースに定義できるのは平坦な2次元の表なので、繰返し部分を持つ表は、繰返しをなくして平坦にする必要がある
- この繰返し部分を排除する操作
- 非正規形:
- 繰返し部分を持つ表
- 第1正規形:
- 第1正規化の結果できた表(繰返し部分を取り除いたもの)
- 非正規形の例:
- 売上表(売上番号、日付、顧客番号、顧客名、[商品番号、商品名、単価、数量]の繰返し)
- 例えば、売上番号S001の行に、P01(ボールペン)とP02(ノート)の2商品が入っている
- 第1正規化のやり方:
- 主キー“売上番号”と、繰返し部分を一意に決められる“商品番号”を複合キーにして、繰返し部分を売上明細表として別の表に分ける
- 主キーの一部である“売上番号”を、元の表の主キーを参照する外部キーにする
- 元の表の主キーを持たせる理由:
- 結合で元の表を再現できるようにするため
- 第1正規形でも残るもの:
- 売上明細表には、主キーの一部である商品番号に関数従属する部分関数従属が残る
- 表記のルール:
- 主キーには実線の下線、外部キーには破線の下線を付ける
- 試験問題に合わせて、主キーの実線が付いている属性には、外部キーの破線は付けない
② 第1正規形の不具合(更新時異常)(★)
- 更新時異常:
- 第1正規形の表は、基本的には関係データベースに定義できる
- でも、データが冗長なので、データ操作のときに不具合が起きる。この不具合のこと
更新時異常の3種類(★)
| 種類 | 何が起きるか(売上明細表の例) |
|---|---|
| 修正時異常 | 商品名「ボールペン」を「油性ボールペン」に変えるとき、該当する行をすべて同時に変えなければならない。1行でも変え忘れると、データに不整合が起きる |
| 挿入時異常 | 主キーが“売上番号”と“商品番号”の複合キーなので、まだ売上のない(売上番号が空値になる)新商品「付箋」は登録できない |
| 削除時異常 | 売上実績が1つしかない商品の売上データを消すと、商品データも消える(「クリップ」が1回しか売れていなければ、その行を消すと「クリップ」という商品の情報がなくなる)。逆に、商品データを残そうとすれば、売上データを消せない |
- 主キーが複合キーの場合:
- それを構成するどの項目も空値は許されない(だから売上番号が空の商品は登録できない)
- 更新時異常の例え:
- 修正時異常は、同じ住所を何冊ものノートに書いていて、引っ越したら全部直さないといけない
- 挿入時異常は、「まだ誰も買っていない新商品」を売上ノートにしか書けないので、載せる場所がない
- 削除時異常は、売上ノートの1行を消したら、その商品があったこと自体がわからなくなる
- 次のステップ:
- 更新時異常を防ぐため、第2正規化と第3正規化を行う
③ 第2正規化
- 第2正規化:
- 第1正規形の表に対して行う操作
- 主キーの一部に部分関数従属する非キー属性を、別の表に分ける
- つまり、すべての非キー属性が、主キーに完全関数従属している状態にする操作
- 第2正規形:
- 第2正規化の結果できた表
- 第2正規化の例:
- 売上明細表の“商品名”と“単価”は、主キーの一部“商品番号”に部分関数従属している
- そこで、これを商品表(商品番号、商品名、単価)として独立させる
- 元の表を再現できるように、売上明細表(売上番号、商品番号、数量)には、商品表の主キーを参照する外部キーとして“商品番号”を残す
- 第2正規化が必要なとき:
- 主キーが複数の属性でできている場合だけ行う
- 1つの属性でできているなら、部分関数従属は存在しないので、すでに第2正規形
- 第2正規形の論理的定義:
- どの非キー属性も、候補キーの真部分集合に対して関数従属しない
- (どの非キー属性も、候補キーに完全関数従属である)
④ 第3正規化
- 第3正規化:
- 第2正規形の表に対して行う操作
- 主キーに推移的関数従属している非キー属性を、別の表に分ける
- つまり、非キー属性間の関数従属をなくし、どの非キー属性も主キーに直接関数従属している状態にする操作
- 第3正規形:
- 第3正規化の結果できた表
- 第3正規化の例:
- 売上表(売上番号、日付、顧客番号、顧客名)は第2正規形だが、「顧客番号 → 顧客名」という非キー属性間の関数従属がある
- そこで、“顧客番号”を主キーにした顧客表(顧客番号、顧客名)として独立させる
- 売上表(売上番号、日付、顧客番号)には、顧客表の主キーを参照する外部キーとして“顧客番号”を残す
- 第3正規形の論理的定義:
- どの非キー属性も、候補キーに推移的関数従属しない
- (どの非キー属性も、候補キーに直接関数従属している)
正規化の流れのまとめ(★)
| ステップ | 取り除くもの | 結果 |
|---|---|---|
| 第1正規化 | 繰返し部分 | 非正規形 → 第1正規形(売上表+売上明細表) |
| 第2正規化 | 主キーの一部への部分関数従属 | → 第2正規形(商品表を分ける) |
| 第3正規化 | 主キーへの推移的関数従属(非キー属性間の関数従属) | → 第3正規形(顧客表を分ける) |
- 最後にできる4つの表:
- 売上表(売上番号、日付、顧客番号)
- 売上明細表(売上番号、商品番号、数量)
- 商品表(商品番号、商品名、単価)
- 顧客表(顧客番号、顧客名)
- 正規化の例え:
- 1冊の雑多なノートを、「売上ノート」「明細ノート」「商品カタログ」「顧客名簿」に分ける。商品名を直すときは、商品カタログの1か所だけ直せばよい
正規形の種類
- 正規形の順番:
- 第1正規形 → 第2正規形 → 第3正規形 → ボイス・コッド正規形 → 第4正規形 → 第5正規形
- 一般的なデータベースなら、第3正規形まで正規化されていれば十分といわれている
- ボイス・コッド正規形:
- 第3正規形でも、候補キーの真部分集合から、他の候補キーの真部分集合への関数従属、あるいは候補キー以外の属性から候補キーの真部分集合への関数従属が残っている可能性がある
- この関係を分解したのが、ボイス・コッド正規形
⑤ 正規化と非正規化
- 正規化の目的:
- データ操作にともなう更新時異常の発生を防ぐこと
- 属性間の関数従属を少なくし、データの重複をなくすことで防ぐ
- 正規化の弱点:
- 正規化を進めると、表がいくつにも分かれる
- 必要なデータを取り出すには表の結合が必要になり、処理時間がかかる
- 非正規化:
- 処理速度が厳しく求められる場合や、更新時異常が起きにくい場合(例えば、更新が少ない表)は、あえて正規化を進めないか、正規化したものを元に戻す
- ここでいう非正規化は、アクセスパターンを考えたうえで、どの表を統合するか、どの属性を表間に重複させるかを考えること
- 非正規化の例え:
- ノートを細かく分けすぎると、1つの調べものに何冊も開く必要がある。よく見る組合せは、あえて1冊にまとめておく(ただし、直すときは両方直す)
例題(正規化の判定)
- 問題:
- 受講表(学生番号、科目番号、学生名、科目名、担当教員番号、担当教員名、成績)がある。主キーは{学生番号, 科目番号}。関数従属は「学生番号 → 学生名」「科目番号 → 科目名、担当教員番号」「担当教員番号 → 担当教員名」「{学生番号, 科目番号} → 成績」。第3正規形にすると、どんな表に分かれるか
- 考え方:
- 繰返しはないので、すでに第1正規形
- 第2正規化:学生名は学生番号だけで、科目名・担当教員番号・担当教員名は科目番号だけで決まる(部分関数従属)ので、学生表と科目表に分ける
- 第3正規化:科目表の中に「担当教員番号 → 担当教員名」(非キー属性間の関数従属)があるので、教員表に分ける
- 答え:
- 受講表(学生番号、科目番号、成績)
- 学生表(学生番号、学生名)
- 科目表(科目番号、科目名、担当教員番号)
- 教員表(担当教員番号、担当教員名)
- 確かめ:
- 元の7つの属性が、どこかの表に必ず1回は入っている(キーは結合用に重複)。外部キー(受講表の学生番号・科目番号、科目表の担当教員番号)で結合すれば、元の表に戻せる
混同しやすいペア
- 独立属性(決定項) / 従属属性(従属項)
- 独立属性は、「x → y」のx(決める側)
- 従属属性は、「x → y」のy(決まる側)
- 関数従属 / 多値従属
- 関数従属は、xが決まると1つのyが決まる(x → y)
- 多値従属は、xが決まると複数の値の集合が決まる(x →→ y)
- 部分関数従属 / 完全関数従属
- 部分関数従属は、複合キーの一部(真部分集合)だけでyが決まる
- 完全関数従属は、キーのどの真部分集合でもyが決まらない(キー全部が必要)
- 推移的関数従属 / 完全推移的関数従属
- 推移的関数従属は、x → y、y → z、y →/ x が成り立つ
- 完全推移的関数従属は、さらに z →/ y も成り立つ
- 部分集合 / 真部分集合
- 部分集合は、元の集合と同じでもよい
- 真部分集合は、元の集合と同じではない部分集合
- 推移律 / 擬推移律
- 推移律は、A → B、B → C ならば A → C
- 擬推移律は、A → B、BC → D ならば AC → D
- 合併律 / 増加律 / 反射律
- 合併律は、A → B、A → C ならば A → BC
- 増加律は、A → B ならば AC → BC
- 反射律は、BがAの部分集合ならば A → B
- 非正規形 / 第1正規形
- 非正規形は、繰返し部分がある
- 第1正規形は、繰返し部分を取り除いた平坦な表
- 第1正規化 / 第2正規化 / 第3正規化
- 第1正規化は、繰返し部分をなくす
- 第2正規化は、部分関数従属をなくす(主キーが複合キーのときだけ必要)
- 第3正規化は、推移的関数従属(非キー属性間の関数従属)をなくす
- 修正時異常 / 挿入時異常 / 削除時異常
- 修正時異常は、同じデータを何行も同時に直す必要がある
- 挿入時異常は、主キーの一部が空になるデータを登録できない
- 削除時異常は、1行消すと、残したい別のデータまで消える
- 第3正規形 / ボイス・コッド正規形
- 第3正規形は、非キー属性が候補キーに推移的関数従属しない
- ボイス・コッド正規形は、さらに、候補キーの一部への関数従属も分解したもの
- 正規化 / 非正規化
- 正規化は、表を分けて重複をなくし、更新時異常を防ぐ(結合が増えて遅くなる)
- 非正規化は、処理速度のために、アクセスパターンを考えて表を統合したり属性を重複させたりする