MySQL の外部キーとリレーション
外部キー(FOREIGN KEY)はテーブル間のリレーションをデータベースレベルで保証する仕組みです。関連するテーブル同士の整合性を自動的に維持してくれるため、不整合なデータの混入を防げます。
外部キーの基本
外部キーは、あるテーブルのカラムが別のテーブルの主キーまたはユニークキーを参照することを宣言します。
CREATE TABLE departments (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
department_id INT NOT NULL,
FOREIGN KEY (department_id) REFERENCES departments(id)
);この定義により、employees テーブルの department_id には departments テーブルに存在する id しか入れられなくなります。存在しない部署 ID を指定すると、エラーになります。
リレーションの種類
テーブル間の関係は、大きく3つのパターンに分類されます。
最も一般的なリレーションです。1つの部署に複数の社員が所属するケースがこれにあたります。「多」側のテーブルに外部キーを配置します。
ユーザーとプロフィールのように、各行が1対1で対応する関係です。外部キーに UNIQUE 制約を付けることで実現します。
学生とコースのように、双方向に複数の関連がある関係です。中間テーブル(結合テーブル)を挟んで2つの1対多リレーションとして表現します。
ON DELETE と ON UPDATE
外部キーで重要なのが、参照先のデータが削除・更新されたときの振る舞いを指定するオプションです。
| オプション | 削除時の動作 | 更新時の動作 |
|---|---|---|
| RESTRICT | 削除を拒否 | 更新を拒否 |
| CASCADE | 子も一緒に削除 | 子のキーも更新 |
| SET NULL | 子のキーを NULL に | 子のキーを NULL に |
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
total DECIMAL(10,2) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE SET NULL
ON UPDATE CASCADE
);この例では、ユーザーが削除されると注文の user_id が NULL になり、ユーザーの id が変更されると注文の user_id も自動的に更新されます。
CASCADE の注意点
ON DELETE CASCADE は便利ですが、意図しない大量削除を引き起こす危険があります。親テーブルの1行を削除したら、子テーブルの数万行が連鎖的に消えるケースも起こりえます。
ブログ記事を削除したらコメントも消す、ユーザーを削除したらセッション情報も消す、など子データが親に完全に従属している場合。
ユーザーを削除したら注文履歴も消す、のようにビジネス上残すべきデータまで削除してしまう場合。この場合は RESTRICT にして、アプリケーション側で制御するのが安全です。
外部キーを使わない設計
大規模なシステムやマイクロサービスでは、外部キー制約をあえて使わないという選択もあります。外部キーは INSERT/UPDATE/DELETE のたびに参照先の存在チェックが走るため、高負荷環境ではパフォーマンスのボトルネックになることがあります。
その場合は、アプリケーション層で整合性を担保し、定期的なバッチ処理で不整合データを検出・修正するアプローチを取ります。ただし、この方針はチーム全体の規律が求められるため、小〜中規模のプロジェクトでは素直に外部キーを使うのが賢明です。



