1. ホーム
  2. postgresql

[解決済み] 移行時のPostgreSQLの外部キーチェックを無効にする

2022-07-09 10:28:21

質問

PostgreSQL 9.4 で外部キーを持つ移行を大量に作成しています。

これは頭痛の種です。なぜなら、テーブルがすべて、移行されるときに外部キーによって期待される正確な順序になければならないからです。私の新しい移行が外部キーに依存する他のパッケージから移行を実行しなければならない場合、さらに厄介なことになります。

MySQL では、これを単純化するために、単純に SET FOREIGN_KEY_CHECKS = 0; をマイグレーションファイルの先頭に追加するだけです。PostgresSQLではマイグレーションコードの長さだけ一時的にこれを行うにはどうしたらよいでしょうか?

ちなみに、これにはLaravel Schema Builderを使用しています。

どのように解決するのですか?

PostgreSQLは設定オプションをサポートしていませんが、別の可能性があります。

postgres=# \d b
        Table "public.b"
┌────────┬─────────┬───────────┐
│ Column │  Type   │ Modifiers │
╞════════╪═════════╪═══════════╡
│ id     │ integer │           │
└────────┴─────────┴───────────┘
Foreign-key constraints:
    "b_id_fkey" FOREIGN KEY (id) REFERENCES a(id) DEFERRABLE

Postgresの参照整合性はトリガによって実装されており、テーブル上のトリガを無効にすることができます。この方法では、任意のデータ(リスク)をアップロードすることができますが、かなり高速です - 大きなデータに対するチェックは高価なためです。そして、もしあなたのアップロードが安全であれば、あなたはそれを行うことができます。

BEGIN;
ALTER TABLE b DISABLE TRIGGER ALL;
-- now the RI over table b is disabled
ALTER TABLE b ENABLE TRIGGER ALL;
COMMIT;

次の可能性は、遅延制約の使用です。これは、制約のチェックをコミット時間に移動させるものです。そのため INSERT コマンドで順序を尊重するべきではありません。

ALTER TABLE b ALTER CONSTRAINT b_id_fkey DEFERRABLE;

BEGIN
postgres=# SET CONSTRAINTS b_id_fkey DEFERRED;
SET CONSTRAINTS
postgres=# INSERT INTO b VALUES(100); -- this is not in a table
INSERT 0 1
postgres=# INSERT INTO b VALUES(10);
INSERT 0 1 
postgres=# COMMIT;
ERROR:  insert or update on table "b" violates foreign key constraint "b_id_fkey"
DETAIL:  Key (id)=(100) is not present in table "a".

挿入されたデータがチェックされるため、この方法を優先してください。