SQLダンプのインポート時に発生する「a foreign key constraint fails」を修正する

インポートが途中で Cannot add or update a child row: a foreign key constraint fails と表示されて止まる。データ自体に問題はなく、間違っているのは INSERT 文の順序です。原因と3つの解決方法を解説します。

データベースをエクスポートし、新しいインスタンスに読み込もうとすると、MySQL が次のエラーを吐きます:

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`app`.`orders`, CONSTRAINT `orders_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`))

あるいは PostgreSQL では:

ERROR: insert or update on table "orders" violates foreign key constraint "orders_user_id_fkey"
DETAIL: Key (user_id)=(42) is not present in table "users".

なぜこれが起きるのか

外部キーは「すべての orders.user_id は既存の users.id を指していなければならない」と定めます。ダンプが users よりorders を挿入すると、参照先の親行がまだ存在せず、データベースはその行を拒否します。

ほとんどのダンプツールはテーブルをアルファベット順作成順で書き出します。外部キーの依存順ではありません。そのため orders(子)がしばしば users(親)より前に来てしまい、インポートが失敗します。

解決策1: 依存関係に従って INSERT を並べ替える(正しい修正)

きれいな解決策は、すべての親テーブルをその子より前に挿入することです。つまり、外部キーを依存関係グラフに解決し、トポロジカル順序でテーブルを読み込みます: users → orders → order_items

数ギガバイトのファイルでこれを手作業でやるのは苦痛です。CREATE TABLEALTER TABLE にまたがるすべての FOREIGN KEY を追跡し、巨大な INSERT ブロックを正しい順序で切り貼りしなければなりません。

解決策2: インポート中に外部キーチェックを無効化する

完全ですでに整合性の取れたダンプであれば、読み込み中の検証を安全にスキップできます。MySQL では、ファイルを次のように囲みます:

-- MySQL
SET FOREIGN_KEY_CHECKS = 0;
-- ... すべての INSERT 文 ...
SET FOREIGN_KEY_CHECKS = 1;

PostgreSQL では、トランザクション内で制約を遅延させます:

-- PostgreSQL
BEGIN;
SET CONSTRAINTS ALL DEFERRED;
-- ... すべての INSERT 文 ...
COMMIT;

その後は今後の書き込みが検証され続けるよう、チェックを再度有効にしてください。これは機能しますが、順序の問題を覆い隠しているだけです。ダンプが部分的な場合は、孤立した行が残ってしまうこともあります。

解決策3: DumpCleaner で両方を自動的に行う

DumpCleaner はダンプを読み込み、CREATE TABLEALTER TABLE からすべての外部キーを抽出し、依存関係グラフを構築して、そのままインポートできるクリーンなファイルを書き出します:

  1. .sql ダンプを DumpCleaner にドラッグします(MySQL、MariaDB、PostgreSQL、SQLite、MS SQL に対応)。
  2. INSERT 順序 → 依存関係順(外部キー対応)を選びます。トポロジカルソートにより、親が子の前に自動配置されます。
  3. 必要なら外部キーチェックを無効化にチェックを入れます。お使いのデータベースに合った文で出力を囲みます。
  4. エクスポートします。新しいファイルをインポートすると、制約エラーは消えています。

循環する外部キーも検出し、不可能な順序を生成する代わりに警告してくれます。

もう手作業の INSERT 手術は不要

DumpCleaner はどんなサイズのファイルでも、外部キーの依存関係に従って INSERT を並べ替えます。ストリーミング処理で、メモリ消費は一定。ネイティブの macOS & iPadOS アプリ、買い切り。

App Store でダウンロード

よくある質問

なぜインポート時に「a foreign key constraint fails」が起きるのですか?

子行がまだ挿入されていない親行を参照しているためです。ダンプは INSERT を外部キーの依存関係ではなく、アルファベット順や作成時刻順で並べているのが原因です。

インポート中に外部キーチェックを無効化しても安全ですか?

完全で整合性のあるダンプなら安全です。元のデータベースですでに有効だったデータの検証をスキップしているだけです。あとでチェックを再度有効にしてください。

ファイルを手作業で編集せずに INSERT を並べ替えるには?

DumpCleaner が外部キーを検出し、依存関係グラフを構築して、INSERT をトポロジカル順序で書き出します。親が常に子より先に読み込まれます。

PostgreSQL でも動作しますか?

はい。DumpCleaner は pg_dump の出力に対応し、依存関係順の INSERT に加えて SET CONSTRAINTS ALL DEFERRED を出力できます。

外部キーの頭痛なしにダンプをインポート

ドラッグして、依存関係で並べ替え、エクスポート。DumpCleaner が外部キーを処理するので、インポートがそのまま通ります。

App Store でダウンロード