データベースの正規化の基礎

この資料では、データベースの正規化の専門用語を初心者向けに説明します。 これらの専門用語の基礎を理解しておくと、リレーショナル データベースの設計について検討するときに役立ちます。

正規化の説明

正規化とは、データベース内のデータを構築する処理のことです。 これには、データを保護し、冗長性と一貫性のない依存関係を排除することでデータベースの柔軟性を高めるために設計されたルールに従って、テーブルの作成とそれらのテーブル間のリレーションシップの確立が含まれます。

冗長なデータがあると、ディスク領域が浪費され、保守上の問題点が生じます。 複数の場所に存在するデータの変更が必要な場合、すべての場所でそれらのデータがまったく同一になるように変更する必要があります。 顧客アドレスの変更は、そのデータが Customers テーブルにのみ格納され、データベース内の他の場所に格納されていない場合に実装する方が簡単です。

"矛盾する従属関係" とは何でしょうか。 ユーザーが顧客テーブルで特定の顧客の住所を確認するのは直感的ですが、その顧客を呼び出す従業員の給与を探しても意味がない場合があります。 社員の給与は、社員に関連付けられているか社員に従属するため、"社員" テーブルに移動する必要があります。 しかし、矛盾する従属関係があると、データを見つけるパスが存在しないか破損していることになり、データの参照が困難になります。

データベースの正規化にはいくつかの規則があります。 各ルールは"標準フォーム" と呼ばれます。最初のルールが観察された場合、データベースは "最初の通常の形式" と言われます。最初の 3 つのルールが観察された場合、データベースは "3 番目の標準形式" と見なされます。正規化の他のレベルは可能ですが、3 番目の正規形式は、ほとんどのアプリケーションに必要な最高レベルと見なされます。

多くの正式なルールや仕様と同様に、実際のシナリオでは必ずしも完全なコンプライアンスが可能とは限りません。 一般的に、正規化を行うと追加テーブルが必要となるため、わずらわしいと感じる顧客もいます。 正規化の最初の 3 つの規則のいずれかに違反した設計をする場合、冗長データや矛盾する従属関係など、アプリケーションで発生する可能性のある問題点を考慮しておく必要があります。

以下は、正規化の例です。

第 1 正規形

  • 各テーブルで繰り返し現れるグループを除去します。
  • 関連するデータごとに 1 つのテーブルを作成します。
  • 関連するデータ セットを主キーで識別します。

同じようなデータを格納するために、1 つのテーブルに複数のフィールドを使用しないでください。 たとえば、在庫項目が 2 つの製造元から納入される場合、在庫レコードで "製造元コード 1" フィールドおよび "製造元コード 2" フィールドを使用して、その項目を追跡するケースを考えてみます。

3 つ目の製造元を追加するとどうなるでしょうか。 フィールドを追加することは答えではありません。プログラムとテーブルの変更が必要であり、動的な数のベンダーにスムーズに対応することはできません。 この場合は、すべての製造元の情報を別の "製造元" テーブルに格納し、項目番号キーを使用して在庫テーブルを 製造元テーブルにリンクするか、製造元コード キーを使用して製造元テーブルを在庫テーブルにリンクします。

第 2 正規形

  • 複数のレコードに該当する値のセットごとに 1 つのテーブルを作成します。
  • これらのテーブルを外部キーと関連付けます。

レコードは、テーブルの主キー (必要に応じて複合キー) 以外に依存しないでください。 たとえば、財務システムにおける顧客の住所を考えてみます。 住所は "顧客" テーブルで必要ですが、"受注"、"出荷"、"請求"、"売掛金"、および "回収" の各テーブルでも必要です。 これらすべてのテーブルに顧客の住所を個別のエントリとして格納するのではなく、"顧客" テーブルまたは個別の "住所" テーブルのいずれか 1 つに格納します。

第 3 正規形

  • キーに依存しないフィールドを削除します。

そのレコードのキーの一部ではないレコード内の値は、テーブルに属していません。 一般的に、一連のフィールドの内容が、テーブル内の複数のレコードに適用されるときは、それらのフィールドを別のテーブルに配置することを検討します。

たとえば、"社員募集" テーブルに、志願者の大学の名前と住所が含まれているとします。 しかし、大学に募集要項を送付するには、大学の完全な一覧が必要です。 大学の情報が "志願者" テーブルに格納されている場合、現在志願者がいない大学の一覧を取得することができません。 この場合、別に "大学" テーブルを作成し、大学コード キーを使用して "志願者" テーブルにリンクします。

例外: 理論的には望ましいものの、3 番目の通常の形式に従うとは限りません。 "顧客" テーブルで、起こり得る内部フィールドの従属関係をすべて除去するには、都市、郵便番号、顧客担当者、顧客クラス、および複数のレコードで重複する可能性があるその他すべての要因に対して個別にテーブルを作成する必要があります。 理論的には、正規化は追求する価値があります。 しかし、小さいテーブルを数多く作成するとパフォーマンスが低下したり、開くことのできるファイルおよびメモリの容量を超える場合があります。

第 3 正規形は、頻繁に変更されるデータに対してのみ適用する方がより現実的です。 従属フィールドが残っている場合、それらのいずれかが変更されるときに、関連付けられたすべてのフィールドの確認がユーザーによって行われるようにアプリケーションを設計します。

その他の正規形

Boyce-Codd 標準形式 (BCNF) とも呼ばれる 4 番目の正規形と呼ばれる 5 番目の標準フォームは存在しますが、実用的な設計では考慮されることはほとんどありません。 これらのルールを無視すると、完全なデータベース設計未満になる可能性がありますが、機能に影響を与えるべきではありません。

サンプル テーブルを正規化する

以下の手順は、架空の学生テーブルを正規化するプロセスの例です。

  1. 正規化されていないテーブル

    Student# Advisor Adv-Room Class1 Class2 Class3
    1022 Jones 412 101-07 143-01 159-02
    4123 Smith 216 101-07 143-01 179-04
  2. 第 1 正規形: 繰り返しグループなし

    テーブルは、2 次元にする必要があります。 1 人の学生が複数のクラスを受講するため、これらのクラスは別のテーブルにまとめる必要があります。 上記のレコードで "Class1"、"Class2"、および "Class3" のフィールドに設計上の問題点があります。

    スプレッドシートでは多くの場合、3 番目のディメンションが使用されますが、テーブルは使用しないでください。 この問題を見るもう 1 つの方法は、一対多のリレーションシップで、一方の側と多くの辺を同じテーブルに配置しないでください。 代わりに、次の例に示すように、繰り返しグループ (Class#) を削除して、最初の標準形式で別のテーブルを作成します。

    Student# Advisor Adv-Room Class#
    1022 Jones 412 101-07
    1022 Jones 412 143-01
    1022 Jones 412 159-02
    4123 Smith 216 101-07
    4123 Smith 216 143-01
    4123 Smith 216 179-04
  3. 第 2 正規形: 冗長なデータを排除する

    上記の表の各 Student# 値の複数の Class# 値に注意してください。 Class# は Student# (主キー) に機能的に依存しないため、このリレーションシップは 2 番目の通常の形式ではありません。

    次のテーブルに、第 2 正規形が示されています。

    学生テーブル

    Student# Advisor Adv-Room
    1022 Jones 412
    4123 Smith 216

    受講登録テーブル

    Student# Class#
    1022 101-07
    1022 143-01
    1022 159-02
    4123 101-07
    4123 143-01
    4123 179-04
  4. 第 3 正規形: キーに依存しないデータを削除する

    上記の例で、Adv-Room (教授の部屋番号) は機能上 Advisor (教授) 属性に従属しています。 この場合の解決法は、以下のように、その属性を "学生" テーブルから "教授" テーブルに移動することです。

    学生テーブル

    Student# Advisor
    1022 Jones
    4123 Smith

    教授テーブル

    名前 Room Dept
    Jones 412 42
    Smith 216 42