简体   繁体   English

我应该暂时禁用外键约束吗?怎么样?

[英]Should I temporarily disable foreign key constraints? How?

I have two tables: 我有两张桌子:

person:
    id serial primary key,
    name varchar(64) not null

task:
    tenant_id   integer not null references person (id) on delete cascade,
    customer_id integer not null references person (id) on delete restrict

(They have a lot more columns than that, but the rest aren't relevant to the question.) (他们有比这更多的列,但其余的与问题无关。)

The problem is, I want to cascade-delete a task when its tenant person is deleted. 问题是,我想级联删除task时,其承租人person将被删除。 But when the tenant and the customer are the same person, the customer_id foreign key constraint will restrict deletion. 但是当租户和客户是同一个人时, customer_id外键约束将限制删除。

My question has two parts: 我的问题有两个部分:

  1. Is temporarily disabling the second foreign key my only option? 暂时禁用第二个外键是我唯一的选择吗?
  2. If so, then how do I do that in PostgreSQL? 如果是这样,那么我如何在PostgreSQL中做到这一点?

Effectively you create a race condition with contradicting rules. 实际上你创造了一个矛盾规则的竞争条件

My first impulse was to check whether a DEFERRED constraint would help. 我的第一个冲动是检查DEFERRED约束是否有帮助。 But it makes sense that it doesn't make any difference. 但它没有任何区别是有道理的

I found that the FK constraint that comes first in the CREATE TABLE script is the winner of this race. 我发现CREATE TABLE脚本中首先出现的FK约束是这场比赛的胜利者。 If the ON DELETE CASCADE comes first, the delete is cascaded, if ON DELETE RESTRICT comes first, the operation is aborted. 如果ON DELETE CASCADE首先出现,则删除是级联的,如果ON DELETE RESTRICT先出现,则操作中止。

Consider the demo on SQL Fiddle . 考虑一下SQL Fiddle的演示。

This seems to correlate with a smaller oid in the catalog table pg_constraint : 这似乎与目录表pg_constraint较小的oid相关:

SELECT oid, * FROM pg_constraint WHERE conrelid = 'task'::regclass

But your feedback indicates, this is not the cause. 但是你的反馈表明,这不是原因。 Maybe pg_attribute.attnum decides the race. 也许pg_attribute.attnum决定比赛。 Either way, as long as it is not documented behavior you cannot rely on it to stay that way in the next major version. 无论哪种方式,只要它没有记录的行为,你就不能依赖它在下一个主要版本中保持这种状态。 Might be worth to post a question on pgsql-general@postgresql.org. 可能值得在pgsql-general@postgresql.org上发布一个问题。

Independent from all that, you need to consider other rows: even if CASCADE would go through for a row in task that has both tenant_id and customer_id pointing to a person , it will still be restricted if any row has only customer_id referencing person . 独立于所有这些,你需要考虑其他行:即使CASCADE在一个同时具有tenant_idcustomer_id指向某person task中的行中,如果任何行只有customer_id引用person ,它仍将受到限制。
Another SQL Fiddle demonstrating the case. 另一个SQL小提琴演示案例。

How to disable the constraint? 如何禁用约束?

Your best bet is to drop and recreate it. 你最好的选择是放弃并重新创建它。 Do it all inside a transaction to make sure you don't corrupt referential integrity. 在事务中完成所有操作以确保您不会破坏参照完整性。

BEGIN;

ALTER TABLE task DROP CONSTRAINT task_customer_id_fkey;

DELETE FROM person WHERE id = 3;

ALTER TABLE task ADD CONSTRAINT task_customer_id_fkey
FOREIGN KEY (customer_id) REFERENCES person (id) ON DELETE RESTRICT;

COMMIT;

This locks the table exclusively and is not fit for routine use in a multi-user environment. 这将独占锁定表,不适合在多用户环境中进行常规使用。

How did I know the name of the constraint? 我怎么知道约束的名字 I took it from pg_constraint as demonstrated above. 我从pg_constraint演示的pg_constraint了它。 Might be easier to use an explicit constraint name to begin with: 可能更容易使用显式约束名称开头:

CREATE TEMP TABLE task (
    customer_id integer NOT NULL
   ,tenant_id integer NOT NULL REFERENCES person (id) ON DELETE CASCADE
   ,CONSTRAINT task_customer_id_fkey FOREIGN KEY (customer_id)
    REFERENCES person (id) ON DELETE RESTRICT
);

There is also 还有

ALTER TABLE task DISABLE trigger ALL;

More in the manual here . 更多在手册中 But that would disable all triggers. 但这会禁用所有触发器。 I had no luck trying to disable only the trigger created by the system to implement a single FK constraint. 我没有运气试图仅禁用系统创建的触发器来实现单个FK约束。

Other alternatives would be to implement your regime with triggers or rules . 其他替代方案是通过触发器规则实施您的制度。 That would work just fine, but those are not enforced as strictly as foreign keys. 这样可以正常工作,但这些并不像外键那样严格执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM