如何在PostgreSQL中安全地重新创建表

时间:2019-03-22 16:14:51

标签: sql 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可以解决此问题。需要弄清楚如何使用它在表重命名和插入之间进行提交。

0 个答案:

没有答案