如何在 Amazon RDS PostgreSQL 中临时禁用外键?

Pio*_*sen 14 postgresql foreign-key amazon-rds

我正在将现有测试环境迁移到 Amazon RDS PostgreSQL。测试框架具有将某些表中的数据重新加载到早期状态的功能。为此,它禁用外键、删除现有数据、加载保存状态并再次启用外键。

目前,测试框架通过禁用所有触发器来禁用外键(当然,这需要超级用户):

alter table tablename disable trigger all;
Run Code Online (Sandbox Code Playgroud)

在 RDS 上,这失败了:

错误:权限被拒绝:“RI_ConstraintTrigger_a_20164”是系统触发器

如何在 Amazon RDS PostgreSQL 中临时禁用外键?

注意:已经提出了类似的问题(RDS 上的 PostgreSQL:如何使用 FK 约束批量导入数据?)但它专门针对离线导入,并且该解决方案也特定于离线导入。

Pio*_*sen 18

session_replication_role

我找到了一种禁用外键的替代方法——https: //stackoverflow.com/a/18709987

set session_replication_role = replica;
Run Code Online (Sandbox Code Playgroud)

并重新启用它们

set session_replication_role = default;
Run Code Online (Sandbox Code Playgroud)

这适用于 RDS,但仍需要特殊权限(即默认情况下未授予)。

删除和重新创建 FK

正如评论中所建议的,替代解决方案是暂时删除 FK。这带来了额外的优势,即在重新启用 FK 时验证数据。

掉落

create table if not exists dropped_foreign_keys (
        seq bigserial primary key,
        sql text
);

do $$ declare t record;
begin
    for t in select conrelid::regclass::varchar table_name, conname constraint_name,
            pg_catalog.pg_get_constraintdef(r.oid, true) constraint_definition
            from pg_catalog.pg_constraint r
            where r.contype = 'f'
            -- current schema only:
            and r.connamespace = (select n.oid from pg_namespace n where n.nspname = current_schema())
        loop

        insert into dropped_foreign_keys (sql) values (
            format('alter table %s add constraint %s %s',
                quote_ident(t.table_name), quote_ident(t.constraint_name), t.constraint_definition));

        execute format('alter table %s drop constraint %s', quote_ident(t.table_name), quote_ident(t.constraint_name));

    end loop;
end $$;
Run Code Online (Sandbox Code Playgroud)

再创造

do $$ declare t record;
begin
    -- order by seq for easier troubleshooting when data does not satisfy FKs
    for t in select * from dropped_foreign_keys order by seq loop
        execute t.sql;
        delete from dropped_foreign_keys where seq = t.seq;
    end loop;
end $$;
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是,这似乎不适用于 Postgres RDS 数据库。将会话设置为副本不会禁用外键,至少在我使用 aws rds 上的 Postgres 12.4 的情况下是如此。 (3认同)