移行のためのPostgreSQL外部キーチェックを無効にする


92

PostgreSQL9.4で外部キーを持つ多くの移行を作成しています。

テーブルはすべて、移行時に外部キーが期待する正確な順序である必要があるため、これは頭痛の種です。新しい移行が外部キーのために依存している他のパッケージから移行を実行する必要がある場合は、さらに厄介になります。

MySQLではSET FOREIGN_KEY_CHECKS = 0;、移行ファイルの先頭に追加するだけでこれを簡略化できます。移行コードの長さだけPostgresSQLでこれを一時的に行うにはどうすればよいですか?

ところで、これにはLaravelスキーマビルダーを使用します。

回答:


83

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".

挿入されたデータがチェックされるため、この方法をお勧めします。


2
どういうわけか、これは私にとって一度はうまくいきましたが、その後はまったくうまくいきませんでした。私はawsaurora postgresにいsuper userます。そこでは、顧客がレプリケーション設定を台無しにできないように、ロールをロックダウンしています。一部のシステムトリガーを無効にするには、スーパーユーザーである必要があるようです。(現在、所有者でもある管理者アカウントを使用しています。なぜ一度機能したのかわかりません。)レプリケーションオプションの設定も、super userロールが必要なため、実行可能なオプションではありません。私の唯一のオプションは...外部キーをドロップして再作成しているようだ
ps2goat

こっちも一緒。やっDISABLE TRIGGER ALLていることはありますが、効果はありません。警告も出ません。無視されます。
jayarjo

アマゾンRDSでは、これは次のエラーを与える:>許可が拒否されました:このレシピは、残念ながら、すべてのケースのためではありませんので、「RI_ConstraintTrigger_a_23031は、」システム・トリガーです:)
kolypto

ローカルデータベースでもエラーが発生しました。ユーザーがデータベースにすべての権限を持つ、**許可が拒否されたました:「RI_ConstraintTrigger_a_16564は、」システム・トリガー**である
Solo.dmitry

154

移行の場合、次の方法ですべてのトリガーを無効にする方が簡単です。

SET session_replication_role = 'replica';

そして、移行後、すべてを再度有効にします

SET session_replication_role = 'origin';

3
聖なる牛、これはより単純であり、目前の特定のタスクにより適しています。(はい)
ijoseph

10
注意:これにはスーパーユーザー権限が必要です。「SETCONSTRAINTSALLDEFERRED」をお試しください。
JJC

9
私はオンになっていますが10.4、上記のステートメントは機能していないようです。
ステファン

2
誰かがこの方法の危険性/リスクを概説し、どのようなシナリオでそれを使用すべきか、そしてどのようにリスクを軽減することができるでしょうか?これが不適切な方法と見なされる場合のベストプラクティスは何ですか?
karns

6
ところで、このパラメーターはAWS RDSのデータベースパラメーターグループに設定して、データベースを再起動せずに適用できます。既存のスキーマと制約が作成された空のデータベースでDMSを使用している場合に非常に便利です。
マイクアトラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.