简体   繁体   English

使数据库中的所有表 UNLOGGED

[英]Make all tables in database UNLOGGED

I want to decrease local test execution time by making all tables UNLOGGED .我想通过使所有表UNLOGGED来减少本地测试执行时间。 I want to write sql script, which will run after all conversion and make them UNLOGGED .我想编写 sql 脚本,它将在所有转换后运行并使它们成为UNLOGGED But I found problem - tables relate each other with FK , so postgresql prohibit make table UNLOGGED (through ALTER ) if it related from other table which is not UNLOGGED yet.但我发现问题 - 表与FK相互关联,因此如果 postgresql 与尚未UNLOGGED其他表相​​关,则禁止 make table UNLOGGED (通过ALTER )。

Is there better way then list all ALTER in correct order - I have more then 150 tables?有没有更好的方法然后以正确的顺序列出所有ALTER - 我有超过 150 个表? For example, apply it on database level.例如,将其应用于数据库级别。

You have to ALTER them in right order I'm afraid.恐怕你必须以正确的顺序改变它们。 You can select https://www.postgresql.org/docs/current/static/catalog-pg-constraint.html and loop for referencing tables first and then alter the rest:您可以选择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;

By all means it will fail if you have recursive FK:如果您有递归 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"

But you would not achieve that any way I believe.但我相信你不会以任何方式实现这一目标。

Also don't forget that after unclean shutdown or failure unlogged tables will be truncated.也不要忘记在不干净的关闭或失败后,未记录的表将被截断。

And lastly you say "after all conversion" - if you create, convert etc, maybe you should just create them unlogged?..最后你说“在所有转换之后”——如果你创建、转换等,也许你应该创建它们而不被记录?..

I would drop and re-create all foreign keys.我会删除并重新创建所有外键。 You can automate this.您可以自动执行此操作。

The following query will generate the necessary DDL statements for all foreign keys.以下查询将为所有外键生成必要的 DDL 语句。 You need to save the output of that into a file, which you can later use to restore all foreign keys.您需要将其输出保存到一个文件中,稍后您可以使用该文件恢复所有外键。

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')

Then generate a script to drop all constraints:然后生成一个脚本来删除所有约束:

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');

Of course you have to run the query to generate the FKs before you drop them ;)当然,您必须删除它们之前运行查询以生成 FK ;)

I had difficulties with the accepted answer, because it relies on a heuristic (which may not apply) to get the ordering correct.我对接受的答案有困难,因为它依赖于启发式(可能不适用)来获得正确的排序。 I have reworked the suggested answer using a (somewhat verbose) recursive query which allows one to get an exact ordering required.我使用(有点冗长)递归查询重新设计了建议的答案,该查询允许获得所需的确切排序。 I have not tested it with recursive FKs, I suspect that the recursive query will not terminate.我没有用递归 FK 对其进行测试,我怀疑递归查询不会终止。 Note that I have restricted the query to apply to tables in the public schema, modify to suit your own needs.请注意,我已将查询限制为应用于public架构中的表,请进行修改以满足您自己的需要。

Unlog all tables:注销所有表:

do
$$
    declare
        _r record;
        _t text;
    begin
        for _r in (
            WITH RECURSIVE constraints AS (
                SELECT
                    tc.table_schema
                     , tc.table_name
                     , kcu.column_name
                     , ccu.table_name AS foreign_table_name
                FROM
                    information_schema.table_constraints AS tc
                        LEFT OUTER JOIN information_schema.key_column_usage AS kcu
                                        ON tc.constraint_name = kcu.constraint_name
                                            AND tc.table_schema = kcu.table_schema
                        LEFT OUTER JOIN information_schema.constraint_column_usage AS ccu
                                        ON ccu.constraint_name = tc.constraint_name
                                            AND ccu.table_schema = tc.table_schema
                WHERE (tc.constraint_type IS NULL OR tc.constraint_type = 'FOREIGN KEY'))
               , tables_and_constraints AS (
                SELECT
                    t.table_schema
                     , t.table_name
                     , c.foreign_table_name
                FROM information_schema.tables AS t
                         LEFT JOIN constraints AS c USING (table_name)
                WHERE t.table_type <> 'VIEW')
               , dependent_table_constraints AS (
                SELECT tc.table_schema
                     , tc.table_name
                     , tc.foreign_table_name
                     , 0 AS depth
                FROM tables_and_constraints AS tc
                WHERE foreign_table_name IS NULL
                UNION
                SELECT tc.table_schema
                     , tc.table_name
                     , tc.foreign_table_name
                     , dtc.depth + 1
                FROM tables_and_constraints AS tc
                         INNER JOIN dependent_table_constraints AS dtc ON tc.foreign_table_name = dtc.table_name
            ) SELECT table_name, max(depth) as depth FROM dependent_table_constraints
            WHERE table_schema = 'public'
            GROUP BY table_name
            ORDER BY depth DESC
        ) loop
                _t := format('ALTER TABLE %I SET UNLOGGED',_r.table_name);
                raise info '%',_t;
                execute _t;
            end loop;
    end;
$$
;

Relog all tables:重新记录所有表:

do
$$
    declare
        _r record;
        _t text;
    begin
        for _r in (
            WITH RECURSIVE constraints AS (
                SELECT
                    tc.table_schema
                     , tc.table_name
                     , kcu.column_name
                     , ccu.table_name AS foreign_table_name
                FROM
                    information_schema.table_constraints AS tc
                        LEFT OUTER JOIN information_schema.key_column_usage AS kcu
                                        ON tc.constraint_name = kcu.constraint_name
                                            AND tc.table_schema = kcu.table_schema
                        LEFT OUTER JOIN information_schema.constraint_column_usage AS ccu
                                        ON ccu.constraint_name = tc.constraint_name
                                            AND ccu.table_schema = tc.table_schema
                WHERE (tc.constraint_type IS NULL OR tc.constraint_type = 'FOREIGN KEY'))
               , tables_and_constraints AS (
                SELECT
                    t.table_schema
                     , t.table_name
                     , c.foreign_table_name
                FROM information_schema.tables AS t
                         LEFT JOIN constraints AS c USING (table_name)
                WHERE t.table_type <> 'VIEW')
               , dependent_table_constraints AS (
                SELECT tc.table_schema
                     , tc.table_name
                     , tc.foreign_table_name
                     , 0 AS depth
                FROM tables_and_constraints AS tc
                WHERE foreign_table_name IS NULL
                UNION
                SELECT tc.table_schema
                     , tc.table_name
                     , tc.foreign_table_name
                     , dtc.depth + 1
                FROM tables_and_constraints AS tc
                         INNER JOIN dependent_table_constraints AS dtc ON tc.foreign_table_name = dtc.table_name
            ) SELECT table_name, max(depth) as depth FROM dependent_table_constraints
            WHERE table_schema = 'public'
            GROUP BY table_name
            ORDER BY depth ASC
        ) loop
                _t := format('ALTER TABLE %I SET LOGGED',_r.table_name);
                raise info '%',_t;
                execute _t;
            end loop;
    end;
$$
;

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

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