わかりやすく 正規化 データベース とは
注文が入るたびに、一つの表にお客さんの名前と電話番号までいっしょに書くとしましょう。同じお客さんが十回注文すれば、同じ名前と番号が十行にそのままくり返されます。そのお客さんが電話番号を変えたら、十行を全部直さなければならず、一行でも見落とすと、その行には古い番号が残ります。問題は、同じ情報を何度も書いたことから始まります。くり返される情報を取り出し、一か所だけに置くように表を分けること、これが正規化です。
同じ情報を何度も書くと
前のレッスンでは、二つの表を共通の列でつないで尋ねました。今回は逆に、そもそも表をなぜそう分けておくのかを見ていきます。注文を受けるたびに一つの表に一行ずつ書き、お客さんの名前と電話番号もいっしょに書くとしましょう。
同じお客さんが何度も注文すると、そのお客さんの名前と番号が、行ごとにまったく同じように書き直されます。下の表でも、ミンスは三件の注文で三回出てきます。
お客さんの名前を押してみましょう。そのお客さんの情報が何行に同じように書かれているかが、ひと目で分かります。
同じ情報が行ごとに書きこまれています。場所をむだに取ることも問題ですが、もっと大きな問題は直すときに起こります。ミンスが電話番号を変えたら、ミンスが書かれた行を全部探して直さなければならず、一つでも見落とすと、同じ人に番号が二つできてしまいます。どちらが正しいのか、表だけでは分かりません。
問題はこれだけではありません。まだ注文していない新しいお客さんは書く行がないので、名前さえ登録できません。また、ハヌルのたった一つの注文を消すと、ハヌルの電話番号までいっしょに消えてしまいます。更新、挿入、削除のときに起こるこうした食いちがいを、それぞれ更新時異常、挿入時異常、削除時異常と呼びます。
くり返す部分を取り出して分ける
解決は思ったより単純です。くり返す部分を取り出して、別の表を作ります。お客さんの名前と電話番号は注文ごとに書かず、お客さんだけを集めた顧客の表に、一人一行で一度だけ書きます。
すると、注文の表からはお客さんの情報がまるごと抜け、注文番号のように注文そのものに属する列だけが残ります。どの情報が何に属するのかを見きわめて、それぞれをあるべき場所に置くわけです。
分けるボタンを押してみましょう。くり返されていたお客さんの情報が注文の表から離れ、顧客の表に一行ずつ集まります。
お客さんの情報が一か所に集まりました。これで、ミンスが番号を変えても、顧客の表の一行を直すだけですみます。注文が百件でも千件でも直すのは一行なので、見落としも、番号が二つに分かれることもありません。新しいお客さんは注文がなくても顧客の表に登録でき、注文を消してもお客さんの情報は残ります。
でも、心配が一つ出てきます。注文の表からお客さんの情報を抜いてしまったので、どの注文がだれのものかは、どうやって分かるのでしょうか。
共通の列でまたつなぐ
ここで、前のレッスンのジョインが役に立ちます。分けるときは、ただ切り離すだけではいけません。二つの表に、同じ列を一つ残しておきます。顧客の表には顧客番号と名前、電話番号を置き、注文の表には名前の代わりに顧客番号だけを書きます。
この顧客番号が、二つの表をつなぐひもです。注文の表の番号を見て、顧客の表で同じ番号を探せば、その注文がだれのものかがすぐに分かります。
注文の行の顧客番号を押してみましょう。同じ番号を持つ顧客の表の行へひもがつながり、だれの注文かが分かります。
番号一つで、二つの表がつながりました。情報は一か所にしか書かれていなくても、ひもをたどれば、いつでも合わせて見られます。くり返しはなくなり、直す場所は一か所に減ったのに、必要な情報はジョインでちゃんと全部そろいます。
これが正規化の要です。実際には、この考え方を正規形という段階的な決まりにまとめてあり、一つのますに値を一つだけ置くことから始めて、表を順に整えていきます。でも、よいことも行き過ぎると問題になります。表をこまかく分けすぎると、どうなるでしょうか。
分けすぎたら、わざと合わせることも
くり返しがいやだからといって、むやみにこまかく分けると、表がどんどん増えていきます。住所は住所の表に、会員の等級は等級の表に、というように、小さなことごとに別の表を作るのです。
すると、お客さん一人をきちんと見るために、表を三つも四つもジョインでつながなければなりません。ジョインにも手間がかかるので、つなぐ表が多いほど答えが出るのは遅くなります。くり返しは減っても、読む速さが落ちたわけです。
こまかく分けるとわざと合わせるを、かわるがわる押してみましょう。分けるほどつなぐ表が増え、合わせると、くり返しが少し出るかわりに一度で見えます。
分けることと合わせることは、あちらを立てればこちらが立たない関係です。こまかく分ければくり返しがなくすっきりしますが、見るたびに表をつなぐので遅くなります。そこで、いつもいっしょに読む情報は、わざと一つの表に合わせておくこともあります。これを非正規化と呼びます。
ただし代償もあります。同じ情報がまたあちこちにできるので、変わるたびにその写しをそろえる仕組みが必要です。書きこみが多いところは正規化寄りに、読み出しがずっと多いところは非正規化寄りにして、バランスをとります。
まとめ
まとめるとこうです。一つの表に同じ情報をくり返し書くと、場所をむだにし、更新や挿入、削除のときに情報が食いちがいます。そこで、くり返す部分を取り出して別の表に分け、共通の列でまたつなぎます。
情報は一か所だけに置き、必要なときにジョインで合わせて見ます。こまかく分けすぎて遅くなれば、わざと合わせることもあります。そのバランスをとるところまでが、正規化です。
要点を順に押して振り返りましょう。(くり返しはむだと食いちがい → くり返しを取り出して分ける → 共通の列でつなぐ → 分けすぎたらわざと合わせる)
これで、表をどう分け、どこでやめるかを判断する目安ができました。情報を一か所だけに置けば、直すときに食いちがうことが減ります。
けれども、一度にいくつもの表をいっしょに直さなければならないこともあります。注文を記録しながら在庫を減らすような場合、二つのうち一つだけ済んで止まると、表どうしが食いちがいます。いくつもの変更を一つにまとめて、全部済ませるか、全部やめるかにする方法を、次のレッスン「トランザクション」で扱います。