参照整合性(外部キー)制約 使う?使わない?

データベースエンジンには参照整合性制約機能が備わっているものがあります。

参照整合性制約を得意先マスタと売上伝票の例で説明すると、得意先マスタに登録していない得意先コードを売上伝票に登録しようとしてもできない、売上伝票に登録している得意先を更新・削除しようとしてもできないなどの制約をデータベースがチェックしてくれるのです。これによってマスタにない得意先コードが売上伝票に存在しない、言い換えると不正なコードを持つレコード(迷子レコード)が存在しないことが保証されます。

これを使うかどうかは時々議論になるようです。制約必要派の言い分はアプリケーションのチェックが楽になる、アプリケーションを介さずにデータを操作したときにも制約が保証される。不要派の言い分は大量の更新・削除処理で負荷が掛かる。開発時の変更が不自由である。アプリケーションでチェックすれば問題がないといったことです。

私は参照整合性制約を積極的に利用しています。

最近の開発案件では、ほとんどが新規開発ではなくてシステムのリプレースであることが多いのですが、従前のシステムに登録されたデータを見ると大抵の場合に迷子レコードが存在しています。

制約不要派は、UI上登録するときにマスタの一覧の中から選ばせるなどの方法で事前チェックが入るからデータベースの制約は2重チェックだという意見があります。これには落とし穴があります。ユーザがコードを選択してからレコードが登録されるまでの間には時間がありますのでこの間に他の端末で今選んだマスタのレコードが更新・削除される可能性に配慮しなければなりません。この場合にも迷子レコードが発生しないようにするには登録の直前にもう一度マスタを確認しなければならなくなります。マスタ確認の前にトランザクションを開始し、ライトロックしてマスタを読み、その後伝票を更新、コミットするという手順を踏まなければいけないわけです。

このような面倒な手間を考えるくらいだったら参照整合性制約に頼ったほうがよいと私は判断しました。

参照整合性制約を使った場合、コード変更はたやすくできなくなります。そのため連鎖更新の機能を使用します。連鎖更新ではマスタを変更すると伝票の方もコードが変更されます。また、使用頻度は多くありませんが連鎖削除という機能もあります。

連鎖更新・連鎖削除は便利な機能ではありますがデータベースエンジンの制限に気をつけなければなりません。Microsoft SQL Server2000では制限がきつく、例えば売上伝票に得意先コードと納品先コードがあり、そのどちらも取引先マスタを参照していると、売上伝票と取引先マスタの間に2つの参照整合性制約をつけることになるのですが、連鎖更新をこの2つの制約に付加することができません。連鎖更新をあきらめるかデータベーストリガで連鎖更新をエミュレートすることになります。意外にもMDBやオープンソースのPostgreSQLにはこのような制限がありません。