簡體   English   中英

使數據庫中的所有表 UNLOGGED

[英]Make all tables in database UNLOGGED

我想通過使所有表UNLOGGED來減少本地測試執行時間。 我想編寫 sql 腳本,它將在所有轉換后運行並使它們成為UNLOGGED 但我發現問題 - 表與FK相互關聯,因此如果 postgresql 與尚未UNLOGGED其他表相​​關,則禁止 make table UNLOGGED (通過ALTER )。

有沒有更好的方法然后以正確的順序列出所有ALTER - 我有超過 150 個表? 例如,將其應用於數據庫級別。

恐怕你必須以正確的順序改變它們。 您可以選擇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"

但我相信你不會以任何方式實現這一目標。

也不要忘記在不干凈的關閉或失敗后,未記錄的表將被截斷。

最后你說“在所有轉換之后”——如果你創建、轉換等,也許你應該創建它們而不被記錄?..

我會刪除並重新創建所有外鍵。 您可以自動執行此操作。

以下查詢將為所有外鍵生成必要的 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 ;)

我對接受的答案有困難,因為它依賴於啟發式(可能不適用)來獲得正確的排序。 我使用(有點冗長)遞歸查詢重新設計了建議的答案,該查詢允許獲得所需的確切排序。 我沒有用遞歸 FK 對其進行測試,我懷疑遞歸查詢不會終止。 請注意,我已將查詢限制為應用於public架構中的表,請進行修改以滿足您自己的需要。

注銷所有表:

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;
$$
;

重新記錄所有表:

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