情報II / 情報システムとプログラミング 2 / 6

データベース設計と正規化

データベース設計と正規化

情報システムの品質は、データベース設計の良し悪しで決まるといっても過言ではありません。設計が悪いと、同じデータがあちこちに重複し、更新のたびに矛盾が生まれます。この講義では、設計図であるER図と、表を整理する手順である正規化(第1〜第3正規形)を学びます。

設計の出発点 — ER図

データベースを設計するときは、まず対象の世界に「どんなもの(実体、エンティティ)」があり、それらが「どう関係(リレーションシップ)」しているかを図にします。これがER図(実体関連図)です。たとえば図書室なら、実体は「生徒」「書籍」、関係は「借りる」です。1人の生徒は多くの本を借り、1冊の本も(時期を変えて)多くの生徒に借りられるので、「生徒」と「書籍」は多対多の関係です。多対多はそのままでは表にできないため、間に「貸出」という表を挟んで1対多と多対1に分解します。

主キーと外部キー(復習と発展)

主キーは各行を一意に識別する列で、「重複しない」「NULL(空)でない」の2条件を満たす必要があります。外部キーは他の表の主キーを参照する列で、表と表を結びつけます。外部キーには「参照先に存在する値しか入れられない」という制約(参照整合性)をかけることで、「存在しない生徒への貸出記録」のような矛盾データを防げます。

正規化 — 表を段階的に整理する

正規化とは、データの重複や更新時の矛盾(更新時異状)が起きないように、表を段階的に分割・整理する手順です。次の注文伝票の例で第1〜第3正規形まで進めてみましょう。

📘 例 文化祭の模擬店の注文伝票をそのまま表にしたとします。
非正規形:注文表(注文ID、日時、会員ID、会員名、{商品ID、商品名、単価、数量}×複数行)
1枚の伝票に複数の商品が並ぶ「繰り返し」があり、このままでは表になりません。

① 第1正規形:繰り返し部分を展開し、1行に1事実だけを入れる。
→ 注文明細表(注文ID、商品ID、日時、会員ID、会員名、商品名、単価、数量)。主キーは(注文ID、商品ID)の複合キー。

② 第2正規形:主キーの一部だけで決まる列を分離する(部分関数従属の排除)。
「商品名・単価」は商品IDだけで決まり、「日時・会員ID・会員名」は注文IDだけで決まる。
→ 注文表(注文ID、日時、会員ID、会員名)/商品表(商品ID、商品名、単価)/注文明細表(注文ID、商品ID、数量)

③ 第3正規形:主キー以外の列で決まる列を分離する(推移的関数従属の排除)。
注文表の「会員名」は、主キーの注文IDではなく会員IDで決まる。
→ 注文表(注文ID、日時、会員ID)/会員表(会員ID、会員名)/商品表(商品ID、商品名、単価)/注文明細表(注文ID、商品ID、数量)

これで「会員名の変更は会員表の1か所を直すだけ」「商品の値上げは商品表の1か所だけ」で済むようになりました。

正規化の効果と注意

正規化の目的は「1つの事実は1か所にだけ記録する」状態を作ることです。これにより、①更新漏れによる矛盾を防げる、②記憶容量の無駄が減る、③データの意味が明確になる、という効果が得られます。一方で、表が分かれるぶん、後述する結合(JOIN)の処理が増えます。検索速度を優先して意図的に正規化を崩す(非正規化する)実務上の判断もありますが、まず正規形で設計するのが原則です。

💡 ポイント
  • ER図で実体と関係を整理してから表を設計する。多対多は中間の表で1対多に分解。
  • 主キー=重複なし・NULLなし。外部キー=他の表の主キーへの参照(参照整合性)。
  • 第1正規形: 繰り返しをなくし1行1事実に。
  • 第2正規形: 複合主キーの一部だけで決まる列を分離(部分関数従属の排除)。
  • 第3正規形: 主キー以外の列で決まる列を分離(推移的関数従属の排除)。
  • 目的は「1つの事実は1か所に」。更新時の矛盾を防ぐ。

練習問題

  1. 「生徒」と「部活動」の関係を考える。1人の生徒が複数の部活動に入れて、1つの部活動には多数の生徒が所属するとき、この関係を表で表すにはどう設計すればよいか答えなさい。
  2. 表「成績表(学籍番号、氏名、科目コード、科目名、得点)」(主キーは学籍番号と科目コードの複合キー)は第2正規形になっていない。理由を説明しなさい。
  3. 正規化を行う目的を「1つの事実」という言葉を使って説明しなさい。

解答・解説

  1. 解答:多対多の関係なので、生徒表と部活動表の間に「所属表(学籍番号、部活動ID)」のような中間の表を作り、1対多と多対1に分解する。
    解説:所属表の学籍番号・部活動IDはそれぞれ生徒表・部活動表への外部キーになる。
  2. 解答:「氏名」は主キーの一部である学籍番号だけで決まり、「科目名」は科目コードだけで決まる。主キー全体ではなく一部にのみ従属する列(部分関数従属)が残っているため第2正規形ではない。
    解説:生徒表(学籍番号、氏名)、科目表(科目コード、科目名)、得点表(学籍番号、科目コード、得点)に分ければ第2正規形になる。
  3. 解答:同じ情報の重複をなくし「1つの事実は1か所にだけ記録する」状態にすることで、更新・削除の際の修正漏れによる矛盾(更新時異状)を防ぐため。
    解説:重複があると、1か所だけ直して他を直し忘れたときにデータが食い違う。

このレッスンのQ&A

読み込み中...