メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
外部キーは、2 つのテーブル間の関係を強制する制約です。あるテーブルの列の値が別のテーブルに存在することを保証し、参照先の行が削除または更新されたときに何が起こるかを定義します。

外部キーの定義

制約名(fk_orders_customer)は省略可能ですが、付ける価値があります。エラーメッセージに表示され、ALTER TABLE 操作が容易になります。 外部キーには InnoDB が必要です。MyISAM は外部キーを黙って無視します。

参照アクション

ON DELETE 句と ON UPDATE 句は、参照先の親行が削除または更新されたときに子行に何が起こるかを定義します。 SET DEFAULT は SQL 標準の一部です。InnoDB はこの構文を問題なく受け入れますが、実装していません。実行時には RESTRICT とまったく同じように動作します(ERROR 1451)。使用しないでください。名前が示すのとは逆のことを黙って行います。 DELETE 時の CASCADE は便利ですが危険です。顧客を削除すると、その顧客のすべての注文が自動的に削除されます。エラーも警告もありません。依存する行が親なしでは本当に意味を持たない場合(たとえば、注文のない注文明細行)にのみ使用してください。 RESTRICT はより安全なデフォルトです。アプリケーションに削除を明示的に処理させるため、意図しないデータ損失を防ぎます。

必須のインデックス

MySQL は外部キー列にインデックスを必要とします。インデックスが存在しない場合、InnoDB が自動的に作成します。
このインデックスが外部キーのチェックを高速にします。インデックスがなければ、すべての INSERT や DELETE でフルテーブルスキャンが必要になります。また、FK 列に対する JOIN クエリも高速化します。そのため、明示的な FK 制約を使用しない場合でも、一対多の関係では常に外部キー列にインデックスを作成すべきです。

外部キーチェックの確認と無効化

一括データロードの間、外部キーチェックはすべての挿入を遅くします。一時的に無効にします。
重要: チェックを無効にすると、孤立した行を挿入できるようになります。チェックを再度有効にしても、既存のデータが遡って検証されることはありません。チェックを無効にした状態でデータをロードした場合は、チェックを再度有効にする前に、参照整合性を手動で検証してください。

既存の外部キーの表示

よくある質問

外部キーはパフォーマンスを低下させますか?

子テーブルへのすべての INSERT は、親テーブルに対するチェック(インデックス検索)を引き起こします。親テーブルからのすべての DELETE は、子行の有無のチェックを引き起こします。高スループットのテーブルでは、これらのチェックが積み重なります。書き込みスループットを優先するチームは、代わりにアプリケーション層で参照整合性を強制することがよくあります。どちらの選択も常に正しいわけではありません。トレードオフは、データベースレベルの安全性と書き込みパフォーマンスの間にあります。

既存のテーブルに外部キーを追加できますか?

はい、ALTER TABLE で追加できます。
orders の既存の行に、customers に存在しない customer_id 値がある場合、ALTER TABLE は失敗します。先にデータを修正してください。

MySQL が外部キーのインデックスを自動的に作成するのはなぜですか?

InnoDB は、親行が削除または更新されたときに子行を素早くチェックする必要があります。FK 列にインデックスがなければ、そのチェックには子テーブルのフルテーブルスキャンが必要です。自動作成されるインデックスがこれを防ぎます。先に(意味のある名前で)独自のインデックスを作成しておけば、InnoDB は 2 つ目を作成せずにそれを使用します。

トラブルシューティング

関連項目