達人に学ぶDB設計徹底指南書を読み、第3章〜第5章に書かれている、DBの正規化、そのメリットデメリットについてまとめました。
なぜ正規化をするのか
何も考えずにDB設計を行うと、以下のような問題が発生するかもしれません。
- 同じデータが複数のテーブルに存在してしまい冗長になってしまう
- データ登録ができなくなってしまう
上記のような冗長性、非一貫性を解決することを正規化と言います。
第1正規形
第1正規形を満たす条件は、「1つのセルには1つの値しか含まない」です。
第1正規形を行う理由は、主キーが列の値を一意に決められない問題を解決することです。
1つの値を決めると、もう1つの値も決まることを関数従属と言います。
正規化は、関数従属性を満たすように整理していく作業とも言いかえることができます。
第2正規形
第2正規形を満たす条件は、「部分関数従属がない」ことです。
第2正規形を満たしていないテーブル
上のテーブルはschool_id
とstudent_number
の2つが主キーです。
このテーブルは、部分関数従属が存在しています。部分関数従属というのは、主キーの一部に関数従属があることです。
上のテーブルでいうと、school_name
はschool_id
だけに関数従属しています。
部分関数従属に対し、student_name
のように2つの主キーをもとに値が決まる関係を、完全関数従属と言います。
第2正規形を満たしているテーブル
上の図は、第2正規形を満たすようにテーブルをstudentテーブルとschoolテーブルへ分割しました。
第2正規形を行うメリットは、冗長性の解消です。これによりデータの登録、更新時の処理が簡単になります。
たとえば、school_name
が変更になったとき、第2正規形を満たしていないテーブルでは、該当するすべて行を更新する必要がありました。
第2正規化を行ったテーブルであれば、schoolテーブルの1行だけを更新するだけで済みます。
また、student_number
がまだ決まっていないがschool_id
とschool_name
を追加したくなったという例が発生した場合(生徒はまだいないが新しい学校が設立されたとする)、第2正規形を満たしていないテーブルではstudent_number
を仮の値にしないと登録できませんでしたが、第2正規化を行ったテーブルであれば、schoolテーブルに新たな値を登録するだけで解決します。studentデーブルは、schoolテーブルの変更を気にしません。
第3正規形
第3正規形を満たす条件は、「推移的関数従属がない」ことです。
第3正規形を満たしていないテーブル
上のテーブルには推移的関数従属が存在しています。推移的関数従属というのは、主キー以外のカラムに関数従属があることです。
上のテーブルでいうと、activity_name
はactivity_code
に関数従属しています。
activity_code
は主キーに関数従属しているため、
主キー
→ activity_code
→ activity_name
という段階的な関数従属が存在しています。
第3正規形を満たしているテーブル
上の図は、第3正規形を満たすようにテーブルをstudentテーブルとactivityテーブルへ分割しました。
第3正規化を行う理由は、第2正規化と同様にデータ登録時の不都合解消にあります。
新たなactivity_name
を登録したいとき、第3正規化を行っていないテーブルでは主キーも同時に登録しないといけません。
第3正規化を行ったことで、新たなactivity_nameを登録・更新するときはactivityテーブルの変更を行うだけになります。
正規化を行うデメリット
正規化を行うデメリットは、SQLのパフォーマンス低下につながることです。
例として、student_name
、school_name
、activity_name
を取得したい場合、第1正規形のみを満たしたstudentテーブルでは、studentテーブルのみを参照するだけで取得できます。
それに対し第3正規形まで満たしているテーブルでは、studentテーブル、activityテーブル、schoolテーブルを結合してデータを取得する必要があります。
SQLでのデータ検索において、テーブルの結合はパフォーマンスが悪化します。
そのため正規化とパフォーマンスにはトレードオフの関係があります。