数据加载后将 PostgreSQL 表设置为 LOGGED

Mic*_*ael 4 postgresql postgresql-9.6 unlogged-tables

我创建了一个空UNLOGGED表来更快地复制大量数据(超过 10 亿行)。加载数据大约需要 4 个小时。

现在我想将表设置LOGGED为使其在意外关闭和崩溃时安全。这个过程需要很长时间。事实上,它比加载数据花费的时间更长。这是正常的,还是有办法加快速度?

Eva*_*oll 6

问题

我相信目前SET LOGGED使用 WAL 重写表(基本上完成整个操作),并重写索引。

所以我在列表中找到了一个关于这个的线程

一个新的 relfilenode 填充了数据 - 旧的,包括 init fork,被重写 rels 的正常机制删除。

上有一个很长的线索-hackers。在不重写和不丢失事务语义的情况下做到这一点真的相当困难。有能力通过重写来做到这一点总比没有它好。

您可以看到添加了SET (LOGGED|UNLOGGED). 实现没有太大变化,尽管有一个修复它的计划,承认存在问题

这个设计给我们带来了大关系的性能问题,因为我们需要将关系的全部内容重写两次,一次写入新堆,另一次写入 WAL,因此该项目将改变当前更改未记录表机制的设计无需重写整个堆即可记录,只需删除 init 分支,如果 wal_level != 最小,我们也会将内容写入 WAL。

但似乎没有更多的工作完成。看代码就知道了

case AT_SetLogged:        /* SET LOGGED */
    ATSimplePermissions(rel, ATT_TABLE);
    tab->chgPersistence = ATPrepChangePersistence(rel, true);
    /* force rewrite if necessary; see comment in ATRewriteTables */
    if (tab->chgPersistence)
    {
        tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
        tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
    }
Run Code Online (Sandbox Code Playgroud)

检查该评论,

 * There are two reasons for requiring a rewrite when changing
 * persistence: on one hand, we need to ensure that the buffers
 * belonging to each of the two relations are marked with or without
 * BM_PERMANENT properly.  On the other hand, since rewriting creates
 * and assigns a new relfilenode, we automatically create or drop an
 * init fork for the relation as appropriate.
Run Code Online (Sandbox Code Playgroud)

所以你可以看到,仍然需要重写。我猜。

潜在的解决方案

您最好将所有数据复制到创建表的相同事务中的表中。这会禁用重写,并在文档中提到。

在最低级别,可以安全地跳过一些批量操作的 WAL 日志记录,这可以使这些操作更快(参见第 14.4.7 节)。可以应用此优化的操作包括:

COPY 进入在同一事务中创建或截断的表

这将跳过 WAL 写入和堆重写。


jja*_*nes 5

这个是正常的。如果您在加载表之后但在设置为记录之前对表 ( ) 进行某种大规模操作update ... from ...,或者由于某种原因无法使用COPY但不得不使用个别INSERT陈述。这些都不适合你,所以我不认为这个两步方法有任何好处。