【问题标题】:How can I disable all contraints in my postgresql?如何禁用我的 postgresql 中的所有约束?
【发布时间】:2019-05-29 16:00:55
【问题描述】:

我有一个 PostgreSQL 数据库,其中包含超过 5000 亿行的表。我正在尝试删除大约 600 万行,但这需要超过 4 分钟。我需要优化那些删除操作以制作一个有用的系统。

我认为一个好主意是禁用约束和触发器,然后再启用它,所以我的问题是:

如何禁用所有约束? 而且,是否可以禁用表之间的关系?

现在,我只是用这个来禁用触发器:

Alter table "table_name" disable all

然后使用它重新启用它:

Alter table "table_name" enable all

编辑

这是启用触发器的查询结果。

  Delete on "ParameterValues"  (cost=0.00..1015910.71 rows=47196359 width=6) (actual time=296995.938..296995.938 rows=0 loops=1)
  Buffers: shared hit=6000000 read=420811 dirtied=93346 written=51646
  ->  Seq Scan on "ParameterValues"  (cost=0.00..1015910.71 rows=47196359 width=6) (actual time=7977.126..19798.361 rows=6000000 loops=1)
        Filter: ("Id" < 23000000)
        Rows Removed by Filter: 34218414
        Buffers: shared read=420811 dirtied=49228 written=51646
Planning Time: 304.085 ms
Execution Time: 296995.963 ms

禁用所有触发器可以提高性能,将执行时间从 5 分钟减少到 3 分钟。

Alter table "table_name" disable trigger all

但是,我需要改进更多的删除操作。有什么想法吗?

【问题讨论】:

    标签: c# postgresql entity-framework-core


    【解决方案1】:

    禁用表上所有触发器的正确​​语句是

    ALTER TABLE atable DISABLE TRIGGER ALL;
    

    这将禁用表上定义的所有触发器和外键约束,因为外键约束是由 PostgreSQL 中的系统触发器实现的。

    它还将禁用 可延迟 主键、唯一性和排除性约束,这些约束也通过触发器实现。不可延迟的主键、唯一性和排除性约束没有关联的触发器并且不受影响。

    您可以稍后通过启用触发器重新启用这些约束,但不会检查任何一致性。因为这很危险,所以禁用此类触发器需要超级用户权限。

    禁用基于触发器的约束的另一种方法是将session_replication_role 参数设置为replica,这也需要超级用户权限。

    禁用检查约束和不可延迟的主键、唯一性和排除性约束的唯一方法是删除它们,然后重新创建它们。后者会花费一些时间来检查表格的一致性,但您仍然可能会胜出,因为它会使数据修改更快。

    有关参考,请参阅ALTER TABLE 的文档。

    【讨论】:

    • ALTER TABLE 不会修改任何行,因此这是意料之中的。如果您没有看到速度增加,那么这可能不是您的瓶颈。也许是 I/O。 在尝试调整之前找出你的瓶颈。
    • 如果不分析瓶颈,你只能猜测。
    • 正如我所说,尝试删除并重新创建约束(可能在与负载相同的事务中),看看这是否能给你带来好处。
    • 如果它对您来说足够快,请接受它。
    • 加快数据修改的另一件事是将max_wal_size设置得相当高。
    【解决方案2】:

    如果你想要一个纯粹的 pl/pgsql 解决方案。您可以使用这样的匿名块(甚至可以使用表名和模式作为参数的函数)。

    DO $$
    DECLARE 
    l_tab_name    TEXT := 'yourtablename';
    l_schema_name TEXT := 'public';
    rec record;
    
    BEGIN
    for rec IN
    (
    SELECT rel.relname as table_name ,con.conname as constraint_name
           FROM pg_catalog.pg_constraint con
                INNER JOIN pg_catalog.pg_class rel
                           ON rel.oid = con.conrelid
                INNER JOIN pg_catalog.pg_namespace nsp
                           ON nsp.oid = connamespace
           WHERE nsp.nspname     = l_schema_name
                 AND rel.relname = l_tab_name
    )
      LOOP
    
           EXECUTE format ('ALTER TABLE %I 
                            DROP CONSTRAINT %I',rec.table_name,rec.constraint_name );
    
      END LOOP;
    END $$;
    

    【讨论】:

    • 我获得了 0 个更新的行。我刚刚拿走了你的代码,并用我的表名替换了 l_tab_name 值。
    • @Jorge Garcia :这不是你验证某事的方式。首先使用具有各种约束的测试表。成功运行此块后,描述表并检查是否可以看到相同的约束
    猜你喜欢
    • 2011-02-10
    • 2020-02-12
    • 2010-09-12
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 2021-12-03
    • 1970-01-01
    相关资源
    最近更新 更多