非正規化

 非正規化とは、正規化を進めることによるデメリットを考慮し、あえて正規化を進めずに留めておくことを指します。
 ここでは、非正規化が有効と考えられるケースと典型的な例、そして注意点を説明することとします。

非正規化が有効と考えられる場合

 正規化を進める主な目的は、データの追加・更新・削除時の問題発生を防ぐことにあります。よって、データの追加・更新・削除を行う必要がないテーブルについては正規化を進める必要性も薄いということになります。具体的な例としては、テーブルそのものを他のシステムからインポートして専ら検索やクエリのデータソース用としてのみ用いるような場合が挙げられます。このような場合はインポートにより得られたテーブルを正規化する必要性は特にありません。また、データの追加・更新・削除があってもその影響を受けない部分については、あえて正規化しないことが考えられます。
 また、正規化を進めると必然的にテーブルが分割されていきますが、テーブルが細分化されていく関係上、必要なクエリの作成が難しくなったりクエリの実行に時間がかかるようになる場合があります。それらが許容できない場合、データの追加、更新、削除時の問題をあえて許容し(あるいはデータマクロなどでチェックすることとして)非正規形のまま運用するということが考えられます。

非正規化の実例

 代表的な例としては次のようなものが挙げられます。

繰り返し列を許容する

 例としては正規化の実例の節で掲げた次のようなテーブルが挙げられます。行(レコード)の追加・削除・変更に伴う問題は山積していますし、販売する商品の数に拡張性がありません(2種までしか記録できない)が、列が足りない場合は随時追加するか複数の販売IDを割り当てて(つまり複数回販売したこととして扱う)対応しようというわけです。

販売テーブル
販売ID取引先コード取引先名取引先所在地商品コード1商品名1単価1数量1商品コード2商品名2単価2数量2
11山田商事○○区△△1牛乳12050002味噌2008000
22斉藤商店◇◇町☆☆2味噌200160003バター1909000
31山田商事○○区△△4りんごジュース802000
43竹田ストア**市□□1牛乳12019004りんごジュース807000

 また、ここまで極端でなくとも、繰り返し列をあえて許容するというのは、是非は別として確かに珍しくありません。商品と取引先に関する情報だけを分割し、販売した商品に関する繰り返し列を残した例は次のようになります。

販売テーブル
販売ID取引先コード商品コード1数量1商品コード2数量2
111500028000
2221600039000
3142000
431190047000

取引先テーブル
取引先コード取引先名取引先所在地
1山田商事○○区△△
2斉藤商店◇◇町☆☆
3竹田ストア**市□□

商品テーブル
商品コード商品名単価
1牛乳120
2味噌200
3バター190
4りんごジュース80
 

 第3正規形まで正規化すると4つになるところですが、1つ少ない3つのテーブルにまとまってはいます。
 いずれ、少ないテーブルで済ませようというのは確かにシンプルな方針ではあります。ただし、上記の例ぐらいのテーブルであれば多少複雑なクエリを作っても実行時間は問題になるほど長くなりませんし、むしろ集計や抽出の際に複数の列を指定する手間が増えるので正規化のメリットを上回るということは考えにくいです。

 また、理屈としては繰り返し列であっても明らかに多くの列数を要しない場合には正規化しないことが考えられます。
 例としては次のようなものが挙げられます。

契約テーブル
契約ID契約名取引先コード担当者コード1担当者コード2
1○○賃貸借契約20124102
2△△売買契約10246102103
3□□賃貸借契約20249101
4○○委託契約20100103104

この例では、1件の契約に2人までの担当者が充てられる制度になっているものとします。担当者コード1及び2は形の上では繰り返し列であるといえますが、上記の販売テーブルの例(一度の販売に何種の商品が含まれるかは注文内容次第)と違ってその列数が自ずと限られていますし、制度改定があったとしてもせいぜい1人増えるかどうかといったところですので拡張性を考慮する必要性が薄いです。また、これらの列を使った計算も重要ではありませんので正規化(分割して担当者テーブルを作る)してもあまりメリットがないと考えられるわけです。
 また、次のような例もあります。これは競技における審判スコアを記録するテーブルです。

得点テーブル
大会コードエントリーNo.選手名審判A得点審判B得点審判C得点審判D得点審判E得点
11金子 博和18.517.017.018.016.5
12押田 信人17.517.016.017.017.5
13菅原 誠一18.016.016.516.016.5
14内田 海斗15.516.015.015.516.5
15磯崎 亮一19.018.517.518.018.5

細かい話になりますが、上記の契約テーブルの例の担当者コードと異なり、このテーブルの得点を表す5つの列は全く均質なものというわけではありません。審判A得点というのはAという審判員がつけた得点ですし、審判B得点というのはBという審判員がつけた得点です。もしその得点を入れ替えてしまうと(順位は不動でしょうけども)競技記録としては別ものになってしまいます。そこで、このような列は繰り返し列ではないとする見方も有力です。
 ただ、いずれにせよ審判の人数に関する拡張性はやはりありませんし、審判の氏名等を審判テーブルに記録しても、このテーブルとでは通常の結合(join)を行うことができないという問題もあります。しかしルール変更も滅多にあるものではないですし、審判個人を軸とした集計分析を行うでもない限り審判テーブルとの結合の必要性もありません。そして入力のしやすさからみてもテーブルを分割するメリットが薄いと判断できる、というわけです。

演算の結果を記録する

 例を挙げてみます。

成績テーブル'
テスト名科目生徒番号点数科目順位
第1学期末国語1753
第1学期末国語2901
第1学期末国語3604
第1学期末国語4852
第1学期末理科1802
第1学期末理科2704
第1学期末理科3851
第1学期末理科4802

 さて、科目順位という列がありますが、ここに記録されている科目ごとの順位(正確には同一テスト同一科目での順位)は計算すれば導きだすことができる値です。テーブルに「生のデータ」として記録するというのは冗長であり、正規化の理屈でいえば第2正規形から第3正規形にする時点で取り除かれます。しかし、あるテストに関するデータの入力が終われば同じテストに関する行が追加されることはありませんし、既存の行の更新・削除も生じないため、後で順位が変動することもありません。よって順位を記録していても何の支障もないというわけです。

過去のデータを上書きせずに残す

 正規化により列は整理され簡潔になりますが、それにより過去の記録を残すことができず問題が生じる場合があります。これを解決するために一見冗長と思われる列をあえて残しておくことがあります。
 以下は正規化の実例の節で示した例の再掲です。

販売明細テーブル
販売ID商品コード販売単価数量
111205000
122008000
2220016000
231909000
34802000
411501900
44807000

商品テーブル
商品コード商品名単価
1牛乳150
2味噌200
3バター190
4りんごジュース80

この例の場合、販売明細テーブルにおける販売単価の列がなくとも、商品コードの値をもとに商品テーブルの単価を参照すれば(現在の)単価を知ることができ、数量と積算することで販売額を計算することができると考えられます。
 しかし、商品テーブルに記録されている単価が変更されると、そのたびに計算結果が変わります。つまり、単価を変更する前に販売した商品の販売額も変わってしまうという問題が生じます。そこで、そうならないように販売のたびに販売単価を記録しているというわけです(販売明細テーブルの1行目と6行目の販売単価が異なっているのは、商品コード1の商品(牛乳)の価格改定が行われた形跡を示しています)。
 ただし、そもそも現在の単価と過去の販売単価は質的に異なる面があります。商品テーブルの単価はいわば定価ですが、販売明細テーブルの販売単価は実販売価格であり、単価の改定だけでなくその販売ごとの要因(値引き等)により変化しうるものといえます。
 そこで、

商品コード→販売単価

ではなく

{販売ID,商品コード}→販売単価

であると捉え、よって上記のテーブルも第3正規形であると見ることもできます。

非正規化に関する注意点

 非正規化は本来、単に正規化しないことをいうのではありません。正規化を進めた結果がどのようなもので、そのデメリットがどの程度であるのかをきちんと把握し比較検討した上であえて正規化の段階を退行させることをいいます。
 それを行わないまま、あるいは正規化そのものを理解しないまま、パフォーマンスを優先しましたとか、正規化のコストとバランスをとりました、というのでは単なる手抜きです。少なくともこのような弁明は、想定されるデータの不整合への対策を講じた上で行わなければなりません。
 そもそも、0コンマ何秒を争うようなパフォーマンスを要求するシビアなシステムがあるとして、クエリの動作が遅いのであればSQLを見直すことを考慮すべきですし、ハード面から改善することも視野に入れるべきです。また、そのようなシビアなシステムであるからこそ、データの不整合という本来致命的な問題を安易に許容すべきではありません。非正規化の実施は慎重に判断しなければなりません。