禁用PostgreSQL外键检查以进行迁移


82

我正在创建很多迁移,这些迁移在PostgreSQL 9.4中具有外键。

令人头疼的是,表在迁移时必须全部按照外键期望的准确顺序排列。如果我必须从我的新迁移所依赖的其他程序包运行迁移来获得外键,则会变得更加棘手。

在MySQL中,只需将其添加SET FOREIGN_KEY_CHECKS = 0;到迁移文件的顶部即可简化此过程。如何仅在迁移代码的长度内临时在PostgresSQL中执行此操作?

顺便说一句,为此使用Laravel Schema Builder。

Answers:


76

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
由于某种原因,这只对我有用,然后根本不起作用。我在aws aurora postgres中,他们在其中锁定super user角色,这样客户就不会弄乱复制设置。看来我必须是超级用户才能禁用某些系统触发器。(我目前使用的管理员帐户也是所有者,我不确定为什么它一次可以使用。)设置复制选项也不是一个可行的选择,因为这也需要super user角色。我唯一的选择似乎是删除并重新创建外键...
ps2goat

同样在这里。做事DISABLE TRIGGER ALL,但没有效果。我什至没有得到任何警告。它只是被忽略。
jayarjo

在Amazon RDS上,这将产生以下错误:>权限被拒绝:“ RI_ConstraintTrigger_a_23031”是系统触发器,因此不幸的是,此食谱并非适用于所有情况:)
kolypto

147

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

SET session_replication_role = 'replica';

迁移后重新启用所有

SET session_replication_role = 'origin';

2
这是圣牛,它既简单又适合于手头的特定任务。(是)
ijoseph '18

8
请注意:这需要超级用户权限。尝试“设置约束所有延迟”。
JJC

8
10.4正在进行,上面的声明似乎不起作用。
Stephane '18

2
有人能够概述此方法的危险/风险,以及在什么情况下应使用该方法以及如何减轻风险吗?如果认为这是不好的做法,那么最佳做法是什么?
卡恩斯

6
顺便说一句,此参数可以在AWS RDS中的数据库参数组中设置,并且无需重新启动db就可以应用!如果您将DMS用于已创建现有架构和约束的空数据库中,则非常有用。
Mike Atlas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.