こんにちは、cocomaruです。
今回はデータベースでデータを適切な関係(テーブル)に分解するための理論である正規化について学んでいきたいと思います。
正規化とは
まずいきなり正規化と言われても、よく分からないと思います。
Wikipediaではどのように定義されているのでしょうか?
正規化(せいきか、英語: normalization)とは、データ等々を一定のルール(規則)に基づいて変形し、利用しやすくすること。
引用元:Wikipedia
つまり関係データベースの正規化では、正規化の理論(ルール)に従って、
関係(テーブル)を分解していき利用しやすくする形に変形することを言います。
言葉だけじゃ分かりにくいので表を用いて説明します。
・発注伝票(注文番号, 商品番号, 商品名, 商品単価, 注文数量)
正規化の理論に従って分解すると以下のようになります。
・商品(商品番号, 商品名, 商品単価)
・発注(注文番号, 商品番号, 注文数量)
関係(発注伝票)を、関係(商品)と関係(発注)に分解した。
正規化の目的
正規化はあるルールに従って、関係(テーブル)を分解することだと学びました。
ではなぜ分解をする必要があるのでしょうか?
それは正規化を行うことによって、「1事実1箇所(1 fact in 1 place)」という、
1つのデータは1ヶ所のみに存在するためのデータ構造を実現し、またそのデータ構造を実現することにより、
更新時異状を無くし、データの冗長性(無駄なこと)排除とデータの独立性を高めることができるからです。
更新時異状は次の三つがあります。
- タプル(行)の挿入
- タプル(行)の更新
- タプル(行)の削除
異状については今後、具体例を用いながら説明していきたいと思いますので、今回はあえて詳細には説明しません。
データの登録、更新、削除時に何か不整合な状態になることを異状と言うんだなと、ざっくり思ってください^^;
ちなみに異常ではなく異状と言います!
正規化の種類
正規化には下記の通り様々な種類があります。
- 非正規化
- 第1正規形
- 第2正規形
- 第3正規形
- ボイス・コッド正規形
- 第4正規形
- 第5正規形
沢山あって、「こんなにあるのか…」とげんなりした方もいるかもしれませんが、
ほとんどの場合において第3正規形の正規化まで行い、それら以外は必要なる場面が少ないです。
ですので第3正規形までの理論をしっかりと身につけていきましょう!
正規化を行わないケース
正規化の重要性をお伝えしていきましたが、あえて正規化を行わない場合があり、以下の3種類があります。
データの更新を行わない
アクセスログなど、データを登録するだけで更新を行わないものは、あえて正規化せずに残す場合があります。
データの履歴を残す必要がある
データの履歴を残す際も正規化を行わない場合があります。
例えばECサイトなどで注文データを保存する「関係(注文)」があったとして、そこに購入した商品の単価も同時に保存します。
正規化の理論で言えば商品の単価は商品情報を管理する「関係(商品)」があり、そこに単価が設定されていますので、
関係(注文)に保存するということは単価情報が2ヶ所に存在することになり、1事実1ヶ所のルールに反します。
ですが関係(注文)に保存するメリットはあります。
商品の単価というのはよく変動するものですので、関係(注文)に購入当時の単価情報を保存しておかないと、
関係(商品)の単価が変更された際に過去の購入金額も変更となるという事象が発生してしまいます。
ですのでデータの履歴を持つためにあえて正規化をしない場合があるのです。
速度性が求められる
その他、正規化をしないケースとしては速度が優先されるケースです。
正規化というのは関係(テーブル)を分解しますが、情報を取得する際は分解された情報を結合するという操作が必要となります。
この結合するという操作は速度が遅く性能に影響がでるため、ソーシャルゲームなど比較的、アクセスが多く、またレスポンスの速度を求められるシステムにおいては正規化をしない手法が取られます。1
関数従属性
正規化を理解する上での重要な概念に「関数従属性」があります。
ある属性Xの値が決定すると、別の属性Yの値が一意に決まる、といった性質です。
※例えば社員番号がわかれば、社員の氏名が分かるなど。
このことをX->Yと表します。
このとき、Xを決定項、Yを従属項と言います、
情報無損失分解
繰り返しになりますが、正規化では関係(テーブル)を分解します。
分解はするのですが、当然結合をしてデータを取得する必要があります。
その際に結合に必要なデータが欠損していたら、もちろんデータは復元できませんよね?
この「分解 ⇔ 結合」ができるように適切に分解することを「情報無損失分解」と言います。
また情報無損失分解を行うために正規化の規則があると言っても良いでしょう。
とは言え、言葉だけでは分かりにくいと思いますので例をあげてみましょう。
・商品(商品番号, 商品名, 商品単価)
・発注(注文番号, 注文数量)
一見すると、それぞれの属性が過不足なく分けられてるので問題ないように見受けられますが、
果たしてここから情報を結合ができるでしょうか?
いえ、関係(商品)と関係(発注)には共通の属性はないため結合ができません。
では自然に結合を行えるためには、どうやって分解すれば良いか?!
正解は既出になりますが以下になります。
・商品(商品番号, 商品名, 商品単価)
・発注(注文番号, 商品番号, 注文数量)
関係(発注)に{商品番号}を追加しました。
この商品番号を元に関係(発注伝票)が復元できるようになります。
分解しても結合して復元できるように情報無損失分解を行うことはとても大切なので、しっかりと概念を覚えておきましょう。
導出属性の排除
正規化の過程で取り除かれることが多い導出属性というものがあります。
よくある例で「単価 x 数量 = 金額」という計算で求められる「金額」は導出属性です。
なぜこの導出属性が排除されるかというと上記の場合、数量が更新されると当然金額の値も変更する必要があり更新時異状が起こる可能性があるためです。
ですが前述した通り、更新しない場合や履歴を残す場合は、あえて導出属性を残す場合もあります。
さいごに
データベースはほとんどの現場でも扱いますし、今回は正規化の目的・種類と正規化を学ぶに当たって必要な知識を紹介していきましたが、
これを機会に理論をしっかりと学んで現場でも一目置かれるデータベースエンジニアを目指していきましょう!
では次回は第1正規化について具体例を用いながら説明していきます!
ここまでお読みいただきありがとうございました!
