首页 > 解决方案 > 如何在 PostgreSQL 中安全地重新创建表

问题描述

我的 PostgreSQL 服务器上有一些表占用的磁盘空间比应有的要多得多。我知道完全真空会回收空间,但是完全真空会在表上设置排他锁,并且这些表会不断被写入,完全真空会导致服务中断过多(其中一个表使用超过 TB 的额外空间)。所以我想出了以下函数来重新创建一个表而不锁定它。

create or replace function recreate_table(t text) returns void as $$
declare
    new_name text;
    old_name text;
    seq_name text;
    tab regclass;
begin
    new_name := 'new_' || t;
    old_name := 'old_' || t;
    seq_name := t || '_id_seq';
    execute format('create table %I (like %I including all)', new_name, t);
    execute format('alter table %I rename to %I', t, old_name);
    execute format('alter table %I rename to %I', new_name, t);
    execute format('alter sequence %I owned by %I.id', seq_name, t);
    execute format('insert into %I select * from %I', t, old_name);
    --- execute format('drop table %I', old_name);
end;
$$ LANGUAGE plpgsql;

它似乎按预期工作,但我想知道这有多安全。这种方法有什么我没有看到的问题吗?

注意:我使用插入是因为有问题的表包含日志数据,因此它们会不断附加到,但现有记录永远不会改变。为了正确地做到这一点,我会使用插入和更新的某种组合,但是我的 postgres 是 9.4 并且不支持 upserts 并且使用插入对于我的目的来说已经足够了。

更新:看起来像alter table独占锁定表并且锁定一直持续到函数完成,因此表在执行插入时保持锁定。此外,显然 PostgreSQL 本身并不支持函数内的提交。使用 dlink API 可以解决此问题。需要弄清楚如何使用它在表重命名和插入之间进行提交。

标签: sqlpostgresql

解决方案


推荐阅读