« モデル駆動(MDA)から仕様書駆動(SDA)へ | トップページ | 業務フローとER図を3D化してみた »

2013.02.22

DDLレベルの外部キー制約は不要

 テーブルを作る際に、DDLレベルで外部キー制約をつけることがあるが、私はこれには反対である。組み込める制約の幅が狭すぎるうえに、業務ルールに関する記述があちこちに散らばってしまうからだ。順を追って説明しよう。

 外部キー制約を組み込むことで、テーブルは更新・追加・削除操作において制約を受ける。たとえば、受注テーブルが顧客idを持っているとして、これに顧客マスターに対する外部キー制約を与えるとしよう。このとき、受注登録の際に顧客idの値がその時点の顧客マスター上に定義されていなければエラーになる。また、特定の顧客データを顧客テーブルから削除しようとしたときに、既存の受注データと関連づけされているような顧客であれば、やはりエラーになる。

[顧客]顧客id,顧客名,...
+   ̄ ̄ ̄

└…[受注]受注id,顧客id,受注日,...
      ̄ ̄ ̄
 この程度の例であれば、外部キー制約をDDLレベルで組み込むことに何ら問題はない。

 ところが、現実は想像以上に複雑である。たとえば、多少不自然な例ではあるが、受注テーブルに「有効区分」のようなものがあってそれが"無効"に設定されていれば、顧客idはブランクでもデタラメでもいいとしたらどうだろう。このような「条件付き外部キー制約」はテーブル定義レベルでは組み込みにくい。

[顧客]顧客id,顧客名,...
+   ̄ ̄ ̄

└…[受注]受注id,顧客id,受注日,有効区分,...
      ̄ ̄ ̄
 もっと自然、かつありがちな例は、私が「動的参照」と呼ぶ構造に関係する。たとえば、顧客の属性として「値引ランク」があるとする。さらに、値引ランクと「受注年月(受注日から導出される)」との組み合わせで決まる「値引率」を管理する「値引率テーブル」があるとする。受注登録に際して、有効な値引率が存在しないような受注を許さないとしたら、これらの動的参照にもとづく外部キー制約はやはり組み込みにくい。

[顧客]顧客id,顧客名,値引ランク,...
+   ̄ ̄ ̄

└…[受注]受注id,顧客id,受注日,(値引ランク),(受注年月),...
┌…    ̄ ̄ ̄


[値引率]値引ランク,年月,値引率,...
     ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
 ようするにDDLレベルの外部キー制約機構は、現実の業務要件を前にしてはイライラさせられるほどに単純で中途半端である。

 それならば、個々のアプリの層に外部キー制約に相当するバリデーションを組み込めばいいかというと、そういうことをやってはいけない。上述した制約の例はあくまでも「DB側の事情」として位置づけできる。それゆえ、それらの事情はDB側の記述として配置されるべきだ。システムのあちこちに散らばるアプリ上で記述してしまえば、データ処理に関する仕様の閲覧性が悪くなる。「カエサルのものはカエサルへ。DBのものはDBへ」だ。

 なお、「DB側の事情」は上述したもの以外に多岐にわたる。たとえば、テーブル操作にともなって一連の操作を実施するというルールがあるとすれば、それらは「DB側の事情」である。具体的には「出荷指示データ」に対して出荷実績報告がされた際に、受払や売上計上を実施する必要があるとすれば、それらの手順は「DB側の事情」である(*1)。

 また、以前にも説明したように「粗利がマイナス値であれば赤い字で示す」とか「この数値は編集せずゼロサプレスで示す」といった「項目の見せ方」に関する諸問題も「DB側の事情」である。MVCにおける「ビュー」の属性と思われるかもしれないが、あくまでもテーブル上のフィールドに従属しているゆえに、それらも「DB側の事情」である。

 ではどうやって? これらの込み入った事情はテーブル定義としては記述できそうにないのに、どうやってそれらをDB側の記述として配置できるのだろう。

 「開発基盤」がその役目を果たせばよい。個々のテーブルには、外部キー制約等を含まない最小限のテーブル定義を置いて、基盤側からそれを透過的に眺められるようにしておく。つまり、DBMSについては「DB処理エンジン」としての利用に徹して、「システム記述の置き場」としては出来る限り使わないようにする。そのうえで、DBMSが抱えきれない上述のような「DB側の事情」を、基盤上で「テーブルの拡張定義」として存分に登録できるようにすればよい。

 なんのためか。まず、求められるアプリ(データ処理機能)を「薄っぺらでありきたり」なものに矮小化・様式化するためだ。結果的に、アプリの開発・保守作業が合理化・省力化される。さらに、DB側の事情をDB上の記述として配置することで、システムの仕様要素の正規化(あるべき場所に置き直すこと)を推し進めるためだ。結果的に、システムの可読性・保守性が向上する。

 とくに後者の意味で開発基盤というものは、システム記述を見通しのいい形で示すための「書庫」の役割を果たさなければいけない。複雑膨大な記述がほうりこまれても、さんざん改修が繰り返されても、可読性・保守性が良好に維持されるかどうか。あまり語られることがないが、これは開発基盤の重大な評価基準である。この基準に比べたら「開発が楽になります」なんて、ありきたりすぎて自慢にならない。


*1.この種の業務ルールは、DBMSの機構であるストアドプロシージャ等を用いて組み込むことも可能だ。しかし、それらのしくみにはDBMS毎の方言があるゆえ、そして、アプリとのきめ細かいやりとりができないゆえ、さらに、上述のようにシステム記述が散らかってしまうゆえに、私は使わない。

|

« モデル駆動(MDA)から仕様書駆動(SDA)へ | トップページ | 業務フローとER図を3D化してみた »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: DDLレベルの外部キー制約は不要:

« モデル駆動(MDA)から仕様書駆動(SDA)へ | トップページ | 業務フローとER図を3D化してみた »