为迁移禁用 PostgreSQL 外键检查

我在 PostgreSQL 9.4中创建了许多具有外键的迁移。

这造成了一个令人头疼的问题,因为在迁移外键时,所有表都必须按照外键预期的顺序排列。如果必须从新的迁移依赖于外键的其他包运行迁移,那么就会变得更加棘手。

在 MySQL 中,我可以通过简单地将 SET FOREIGN_KEY_CHECKS = 0;添加到迁移文件的顶部来简化这一过程。我如何能做到这一点暂时在 PostgreSQL 只为长度的迁移代码?

顺便说一句,使用 Laravel 模式生成器完成此操作。

139410 次浏览

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

您应该首选此方法,因为将检查插入的数据。

对于迁移,使用以下命令禁用所有触发器更容易:

SET session_replication_role = 'replica';

在迁移之后

SET session_replication_role = 'origin';