使数据库中的所有表都UNLOGGED

时间:2017-05-15 08:50:32

标签: postgresql

我想通过制作所有表UNLOGGED来减少本地测试执行时间。我想编写sql脚本,它将在所有转换后运行,并使它们成为UNLOGGED。但我发现问题 - 表与FK相互关联,因此postgresql禁止make table UNLOGGED(通过ALTER),如果它与其他表格UNLOGGED相关。

有更好的方法然后按正确的顺序列出所有ALTER - 我有超过150个表吗?例如,将其应用于数据库级别。

3 个答案:

答案 0 :(得分:1)

你必须以正确的顺序改变它们我害怕。 您可以选择https://www.postgresql.org/docs/current/static/catalog-pg-constraint.html并首先循环引用表,然后更改其余表:

begin;
do
$$
declare
 _r record;
 _t text;
begin
 for _r in (
    select relname,conrelid
    from pg_constraint
    join pg_class c on c.oid = conrelid
    where confkey is not null
    order by conrelid desc
    -- Order by oid with logic that you should start from latest added objects to earliest - of course it does not garantee anything
 ) loop
    _t := format('alter table %I set unlogged',_r.relname);
    raise info '%',_t;
    execute _t;
 end loop;

  for _r in (select tablename from pg_tables where tablename like 's%' and schemaname = 'public') loop
    _t := format('alter table %I set unlogged',_r.tablename);
    raise info '%',_t;
    execute _t;
 end loop;

end;
$$
;
rollback;

如果你有递归FK,那么无论如何都会失败:

t=# create table s134(i int primary key, e int);
CREATE TABLE
t=# create table s135(i int references s134(i), e int primary key);
CREATE TABLE
t=# alter table s134 add constraint c1 foreign key (e) references s135(e);
ALTER TABLE
t=# alter table s134 set unlogged;
ERROR:  could not change table "s134" to unlogged because it references logged table "s135"
t=# alter table s135 set unlogged;
ERROR:  could not change table "s135" to unlogged because it references logged table "s134"

但你不会以任何方式实现这一点。

另外不要忘记,在不干净的关闭或失败之后,未记录的表将被截断。

最后你说“毕竟转换” - 如果你创建,转换等,也许你应该创建它们未记录?...

答案 1 :(得分:1)

我会删除并重新创建所有外键。你可以自动化这个。

以下查询将为所有外键生成必要的DDL语句。您需要将其输出保存到文件中,以后可以使用该文件还原所有外键。

select format('alter table %I.%I add constraint %I ',  ns.nspname, tb.relname, conname)|| 
       pg_get_constraintdef(c.oid, true)||';' as ddl
from pg_constraint c
  join pg_class tb on tb.oid = c.conrelid
  join pg_namespace ns on ns.oid = tb.relnamespace
where ns.nspname not in ('pg_catalog', 'information_schema')
  and ns.nspname not like 'pg_temp%'
  and c.contype in ('f')

然后生成一个脚本以删除所有约束:

select format('alter table %I.%I drop constraint %I cascade;', ns.nspname, tb.relname, c.conname) as ddl
from pg_constraint c
  join pg_class tb on tb.oid = c.conrelid
  join pg_namespace ns on ns.oid = tb.relnamespace
where ns.nspname not in ('pg_catalog', 'information_schema')
  and ns.nspname not like 'pg_temp%'
  and c.contype in ('f');

当然你必须运行查询以在删除之前生成FK ;)

答案 2 :(得分:0)

我在接受的答案上遇到困难,因为它依赖于启发式方法(可能不适用)来正确排序。我使用了(有点冗长)的递归查询对建议的答案进行了重新设计,该查询允许人们获得所需的确切排序。我没有使用递归FK对其进行测试,我怀疑递归查询不会终止。请注意,我已将查询限制为应用于lens模式中的表,并根据您的需要进行修改。

注销所有表:

lens

重新记录所有表:

public