テーブルの正規化について説明してみた。

バックエンド
date 2014.04.29 tag MySQL

テーブルの正規化は初心者の人にとっての鬼門。ちょうど新人研修で教えていたこともあったので正規化は何のためにあるのか、どういう状態なのかを説明したエントリーを書いてみました。

そもそも正規化とはなにか

「正規化」という単語を一般的な言葉で見てみるとこのような意味があるので、僕はデータベースのデータを利用しやすくするための手段の1つという言う捉え方をしています。
そのためデータベースを利用するためには”必ず正規化をしないといけない”というワケではないのです。

正規化(せいきか、英: normalization)とは、データ等々を一定のルール(規則)に基づいて変形し、利用しやすくすること。

テーブルの正規化

リレーショナルデータベースの正規化を考えてみましょう。
データを利用しやすくするためにはデータの繰り返しが無い状態が望ましいですよね。例えばデータが繰り返し重複して登録されていると無駄ですし、そのようなデータが更新されることになると全ての影響箇所も更新しなければデータの不整合が発生します。

normalize

正規化とはこのような複数箇所の更新による不整合を極力防ぐために、根本的なデータは重複なしで別のテーブルとして管理する設計手法です。リレーショナルデータベースは違うテーブルでも共通の値があれば結合できますよね。

また逆に言うと正規化して分割したテーブルは、結合することによって元のテーブルのデータを表現できなければいけません。本来の目的を失ってしまってはダメなんですね。

テーブルを正規化するメリットとデメリット

正規化をするメリットとデメリットについて挙げてみます。

メリット

  • 更新は根本的なデータだけ行えばよくなり、不整合が防ぎやすくなる
  • 正規化されたテーブルにあるデータ量は元のテーブルよりも減少するので更新が高速

デメリット

  • 正規化でテーブルを分割すると、元のデータ構造を表現するための結合が必要になる = SQLが複雑になる
  • 分割することでインデックスがうまく選択することができない場合がある

これらのメリット・デメリットがあるため正規化は適材適所で行うべきです。注意したいのはMySQLを含むリレーショナルデータベースでは正規化されていないテーブルも扱えるということです。

実際にテーブルの正規化をしてみる

実際にデータの重複により問題が発生しやすいテーブルの正規化を考えてみます。具体例として次の商品の注文テーブルを正規化していきます。

正規化する前のテーブル

まずはこの状態が1つのテーブルに入っている状態だということを確認しましょう。このテーブルでは「商品名」と「価格」の値が重複して存在しているため、データ更新を複数回しないとデータの不整合が発生します。「JOJOの奇妙な冒険 53巻」に修正したら2回分、UPDATEを実行する必要がありますね。

1. 注文テーブル
注文ID 商品名 価格
1 ジョジョの奇妙な冒険 49巻 432
2 ジョジョの奇妙な冒険 53巻 432
3 ジョジョの奇妙な冒険 53巻 432

それでは正規化してみましょう。

正規化したテーブル

重複したデータに注目してテーブルを切り分け、その結果として2つのテーブルとなりました。正規化ってやってみると以外と簡単です。(無意識にやってることが多いかも)

1. 注文テーブル
注文ID 商品ID
1 1049
2 1053
3 1053
2. 商品テーブル
商品ID 商品名 価格
1049 ジョジョの奇妙な冒険 49巻 432
1053 ジョジョの奇妙な冒険 53巻 432

正規化したテーブルを結合して元の状態を表現するため、共通の商品IDを持たせています。次のSQL文で結合することができます。

MySQL注文テーブルと商品テーブルの結合

SELECT 注文.注文ID 商品.商品名 商品.価格 FROM 注文 LEFT JOIN 商品 ON 注文.商品ID=商品.商品ID;

またこの状態では商品名が変更になったとしても商品テーブルの商品を1カ所変更するだけで↑の結合結果にその結果がすべて反映される形になります。データの一元管理になるわけですね。

正規化の種類

最後に正規化の種類について簡単に説明します。正規化はテーブルの状態によって第○正規形と区別することができ、一般的には第3正規化までやれば良いって本に書いてあります。仕事とかでは第2・第3正規形までやることが多いかも。

正規化名 状態
第1正規化 データの重複が無い状態のテーブル
第2正規化 主キーによって他の値が決まる状態のテーブル
第3正規化 主キーによって他の値が決まる状態かつ主キーにより直接決まる状態のテーブル

実際に正規化してみたテーブルでは既に第3正規形になっていたのでした。

  • 注文テーブルでは主キー「注文ID」によって商品IDが決定する。
  • 商品テーブルでは主キー「商品ID」によって商品名と価格が決定する。