代码之家  ›  专栏  ›  技术社区  ›  azp74

PostgreSQL-禁用约束

  •  41
  • azp74  · 技术社区  · 16 年前

    我需要从两个表中删除大约75000行。我知道,如果我在启用fk约束的情况下尝试这样做,将会花费不可接受的时间。

    来自Oracle的背景,我的第一个想法是禁用约束,执行delete&然后重新启用约束。如果我是超级用户(我不是,但我是以拥有/创建对象的用户身份登录),PostGres似乎允许我禁用约束触发器,但这似乎不是我想要的。

    另一种选择是删除约束,然后恢复它。考虑到我的表的大小,我担心重建约束会花费很长时间。

    编辑:在比利的鼓励下,我试着在不改变任何约束的情况下删除,这需要超过10分钟。但是,我发现要从中删除的表有一个自引用外键。。。重复(&A);非索引)。

    6 回复  |  直到 16 年前
        1
  •  65
  •   Dave Jarvis James Eichele    14 年前

    根据之前的评论,这应该是个问题。也就是说,有一个命令可能就是您想要的—它将约束设置为deferred,以便在提交时检查它们,而不是在每次删除时检查它们。如果你只是对所有的行进行一次大的删除,这不会有什么区别,但是如果你是分块进行的,它会有区别。

    SET CONSTRAINTS ALL DEFERRED
    

    这就是你要找的。请注意,约束必须标记为 DEFERRABLE

    ALTER TABLE table_name
      ADD CONSTRAINT constraint_uk UNIQUE(column_1, column_2)
      DEFERRABLE INITIALLY IMMEDIATE;
    

    CREATE OR REPLACE FUNCTION f() RETURNS void AS
    $BODY$
    BEGIN
      SET CONSTRAINTS ALL DEFERRED;
    
      -- Code that temporarily violates the constraint...
      -- UPDATE table_name ...
    END;
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    
        2
  •  25
  •   gersonZaragocin Jitesh    8 年前

    对我起作用的是一个接一个地禁用 TRIGGERS 那些将要被卷入战争的桌子 DELETE 操作。

    ALTER TABLE reference DISABLE TRIGGER ALL;
    DELETE FROM reference WHERE refered_id > 1;
    ALTER TABLE reference ENABLE TRIGGER ALL;
    

    解决方案在版本9.3.16中工作。我的时间从45分钟到14秒 操作。

    如@amphetamachine在评论部分所述,您需要 admin 表执行此任务的权限。

        3
  •  10
  •   Jonathan Fuerth    8 年前

    如果你尝试 DISABLE TRIGGER ALL permission denied: "RI_ConstraintTrigger_a_16428" is a system trigger

    set session_replication_role to replica;
    

    如果此操作成功,将禁用表约束下的所有触发器。现在由您来确保您的更改使DB保持一致的状态!

    完成后,重新启用触发器;您的会话限制:

    set session_replication_role to default;
    
        4
  •  5
  •   Community Mohan Dere    9 年前

    (这个答案假设您的目的是删除这些表的所有行,而不仅仅是一个选择。)

    我也必须这样做,但作为测试套件的一部分。我找到了答案,他建议道 elsewhere on SO . 使用 TRUNCATE TABLE 具体如下:

    TRUNCATE TABLE <list-of-table-names> [RESTART IDENTITY] [CASCADE];
    

    下面的命令将从表中快速删除所有行 table1 , table2 ,和 table3 ,前提是未列出的表中没有对这些表的行的引用:

    TRUNCATE TABLE table1, table2, table3;
    

    但是,您可以限定查询,以便它也会截断所有引用所列表的表(尽管我没有尝试此操作):

    TRUNCATE TABLE table1, table2, table3 CASCADE;
    

    默认情况下,这些表的序列不会重新开始编号。新行将以序列的下一个编号继续。重新开始序列编号:

    TRUNCATE TABLE table1, table2, table3 RESTART IDENTITY;
    
        5
  •  3
  •   Weekend Baf    7 年前

    我的PostgreSQL是9.6.8。

    set session_replication_role to replica;
    

    为我工作,但我需要许可。

    sudo -u postgres psql
    

    然后连接到我的数据库

    \c myDB
    

    并运行:

    将session\u replication\u role设置为replica;
    

    现在我可以用约束从表中删除。

        6
  •  -11
  •   Alam Usmani    11 年前

    禁用所有表约束

    ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName
    

    --启用所有表约束

    ALTER TABLE TableName CHECK CONSTRAINT ConstraintName