【実務・中級編】 外部キー制約 – PostgreSQL

外部キー制約、ちゃんと「戦略的」に貼れてる?:PostgreSQLで学ぶ整合性の守り方

やあ。最近、データベースのパフォーマンスチューニングの相談を受けることが増えたんだけど、ふと気づいたことがあるんだ。「外部キー制約(Foreign Key)」を単なる「データの紐付けツール」だと思っていないかな?

確かに、外部キーはデータの整合性を保つための最強のガードレールだ。でも、それをどう設定するか、あるいは「あえて貼らない」という選択をするとき、そこにDBエンジニアとしての設計思想が宿る。今日は、実務で絶対に知っておくべき外部キーの作法について、少し深い話をしよう。

—

1. 「守る」ための設計:ON DELETEとON UPDATEの使い分け

外部キー制約の醍醐味は、親レコードが消されたときにどう振る舞うかを定義できることだ。ここを適当に決めると、後々データが整合性を失って大惨事になる。

よくあるユースケースで考えてみよう。

  • CASCADE(連鎖削除):

親がいなくなったら子も不要。例えば「ブログ記事」が削除されたら、それに紐づく「コメント」も消えていい、という場合だ。

  • SET NULL:

親は消えるけど、子の記録は残したいケース。「退職した社員」が作成した「タスク」を誰がやったか残しておきたいなら、`user_id` をNULLにするのが正解だ。

  • RESTRICT / NO ACTION:

「まだ参照されているから削除させない」。これがデフォルトだけど、実は一番堅実だ。迂闊に消してほしくない重要なデータには、あえてこれを明示しておくのがプロの慎重さだね。

ALTER TABLE comments
ADD CONSTRAINT fk_post
FOREIGN KEY (post_id) REFERENCES posts(id)
ON DELETE CASCADE;

—

2. 見落とされがちな「インデックス」の罠

ここからが本題だ。現場のレビューで僕が必ずチェックするのが、「外部キーカラムにインデックスを貼っているか」という点。

PostgreSQLは、外部キー制約そのものには自動でインデックスを貼ってくれない。これがなぜ問題かというと、親テーブルのデータを削除したり更新したりするとき、PostgreSQLは「このIDを参照している子テーブルのレコードがないか」をチェックするために、子テーブルを全スキャン(Seq Scan)し始めるんだ。

親テーブルのデータを消すたびに全テーブルがスキャンされる……想像しただけで背筋が凍るだろう?

原則:外部キーカラムには、基本的にインデックスを貼る。

もしクエリの実行計画で `Seq Scan` が出ていたら、まずはここを疑うべきだ。ただ、頻繁に参照・更新が発生するテーブルなら、インデックスの更新コスト(書き込み負荷)とのトレードオフになる。このバランスを見極めるのが、データベースエンジニアの腕の見せ所だよ。

—

3. 実務で使うときの「ちょっとした裏技」

大規模なシステムになると、外部キーを貼ることで逆に運用が辛くなることもある。「論理削除」を多用するシステムだと、外部キーの制約とバッティングしてデッドロックが多発したりね。

そんなときは、以下のポイントを思い出してほしい。

  • NOT VALID を活用する:

巨大な既存テーブルに後付けで外部キーを貼ると、テーブル全体がロックされてシステムが止まってしまう。まずは `NOT VALID` で制約を追加してロックを最小限にし、その後に `VALIDATE CONSTRAINT` で時間をかけて検証する。これだけでリリース時のヒヤヒヤが激減するはずだ。

— テーブルをロックせずに制約を追加
ALTER TABLE orders ADD CONSTRAINT fk_user
FOREIGN KEY (user_id) REFERENCES users(id) NOT VALID;

— 後からバックグラウンドで検証
ALTER TABLE orders VALIDATE CONSTRAINT fk_user;

—

最後に:制約は「枷」ではなく「武器」だ

新人エンジニアの頃は「外部キーがあるとデータの投入順序を気にしなきゃいけないから面倒だな」と思うかもしれない。でも、データが壊れたときに復旧させるコストと、制約を設計する手間を天秤にかけてみてほしい。

制約を適切に設計することは、将来の自分(や、深夜に障害対応で叩き起こされる同僚)への一番のプレゼントになる。

データベースは嘘をつかない。君が正しく設計すれば、データベースは一生懸命君のデータを守ってくれる。ぜひ、明日のコードから意識してみてくれ。

また何か疑問があれば、いつでも聞いてくれよ。エンジニア同士、一緒にいいシステムを作っていこう。

コメント

タイトルとURLをコピーしました