16bit!

エンジニアじゃなくなっちゃった人が何かを書くブログ

【Oracle】Foreign Key制約(参照整合性制約)について

Foreign Key制約(参照整合性制約)とは

Oracleの整合性制約の1つにForeign Key制約というものがありまして*1
簡単に言うと、
参照先のテーブルにデータが存在しないようなデータの入力をできないようにする
という制御です。

例を挙げると、
従業員テーブルと部署テーブルがあり、従業員テーブルはそれぞれの従業員が所属する部署IDを持っている、
というようなテーブル構造の場合、
従業員テーブルの部署IDカラムを外部キー、部署テーブルの部署IDカラムを参照キーに指定することで、
存在しない部署IDを持った従業員を登録することができなくなります。

テーブル間のデータの不整合はなかなか見つけづらいものでもあるので、
それが絶対に発生しないような制御をDB側でやってくれるというなら、
普通に考えればとても良さそうな話に見えます。

<参考>
整合性制約 - オラクル・Oracleをマスターするための基本と仕組み
オラクル整合性制約メモ(Hishidama's Oracle constraint Memo)


ただ、上の例のように外部参照するテーブルが1つだけなんてことは実際にはほとんどなく、
従業員テーブルなら役職テーブルも参照しているだろうし、
ちょっとしたアプリケーションなら勤務体系テーブルなんてのも参照してるかもしれない。
さらにもしかしたら、現住所を都道府県テーブル、市区町村テーブルなどそれぞれのテーブルを参照する形式で持っている可能性もあります。

そうすると制御をかけるだけでも結構な手間だし、
当然制御の数が増えれば増えるだけ従業員データを登録する際にチェックすることが増え、
その分パフォーマンスも悪くなってきます。

<参考>
整合性制約の有無によるINSERTの速度差 - kagamihogeの日記

参考先の実験では100万件のINSERTで10~15秒程度の差ですが、
先述した通り、実際にはもっと多くの制御をかける必要があるし、テーブル構造だってもっと複雑なので、
実際にはもっと差が開きます。

他にもデータ移行時にちゃんと順番考えないとエラーになっちゃう*2とか、
制約をかけることによるデメリットはいくつかありますが、
基本的には最大のデメリットは手間(開発側)と速度(ユーザー側)かな?と思います。

私見

そもそもDBがチェックをしようがしまいが、
アプリケーションのロジック側でDB不整合が起きないようにはしてあるはずなので、
基本的には参照整合性制御はセーフティネットくらいの意味合いであるべきで、
「念のため制約かけておく」くらいのものかと思っています。

なので、個人的にはこれまではメリットよりもデメリットの方が大きいなーと考えて、
参照整合性の制御は基本的には不要にしたいと思っていたのですが、
最近になって、「もしかしたら制約かけた方がいいかもしれない」と思い始めました。

というのも、アプリケーション経由だけでなく、
データリカバリなどで直接データを書き換えるケースの場合、
「そもそも不整合なんて起きないようにロジック組んでるよね?」という安全バーが無いので、
単純に人的ミスで不整合が起きえます。

データリカバリ自体は別に最近急に増えたわけでもないのですが、
テーブル構造が複雑になってくるとミスの発生確率も上がりますし、
もっと言うと、リカバリ作業に慣れてきた頃が一番危ない気もするので、
そういった、アプリケーションを通さないデータの書き換えの場合の制御として、
DBそのものに制約をかけておくことは必要なのかもしれません。

そもそも大量のデータを一気に登録・更新する場合は別ですが、
画面からユーザーのオペレーションでデータを数件更新するような場合には、
制約かけていても実行時間に不満が生じるほどの差はありません。
であればあとは開発側の「えーめんどくさい」というデメリットだけなので、
そんなもんならやった方が良い気がします。


終わり。

*1:Oracle以外のRDBMSにも参照整合性制約を持っているものは多いです

*2:http://itpro.nikkeibp.co.jp/article/COLUMN/20090512/329851/