PostgreSQL:为什么 CREATE TABLE AS 比 CREATE ... INSERT INTO 快?

use*_*074 5 postgresql insert write-ahead-logging bulk-insert ctas

以下是同一事物的两种不同语法。

  1. 带有COPY TABLE AS SELECT( CTAS)。

    CREATE TABLE main
    AS
      SELECT *
      FROM other;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 作为单独的语句CREATE TABLEINSERT INTO

    CREATE TABLE main (like other);
    
    INSERT INTO main
    SELECT *
    FROM other;
    
    Run Code Online (Sandbox Code Playgroud)

我观察到的CTAS比明显快CREATE TABLE.. INSERT。第一个需要 20 秒才能完成执行。第二个语法二需要 1 分 15 秒才能完成执行。

差异的原因可能是什么?

Eva*_*oll 5

CREATE TABLE AS与其他形式相比有一些优点,即减少或消除 WAL。。当然,优化可以应用于某些 wal-reduction 模式(最小)下的一些命令(即,CREATE TABLE ASCREATE INDEX同一事务中创建或截断的表)。CLUSTERCOPY into

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

但最小 WAL 不包含足够的信息来从基础备份和 WAL 日志重建数据,因此必须使用副本或更高版本来启用 WAL 归档 (archive_mode) 和流复制。

您可以在此处阅读有关此内容的更多信息

14.4.7。禁用 WAL 归档和流复制

将大量数据加载到使用 WAL 归档或流复制的安装中时,加载完成后进行新的基础备份可能比处理大量增量 WAL 数据更快。要防止加载时增量 WAL 日志记录,请通过设置wal_level为最小、archive_mode关闭和max_wal_senders零来禁用归档和流式复制。但请注意,更改这些设置需要重新启动服务器。

除了避免归档器或 WAL 发送器处理 WAL 数据的时间之外,这样做实际上会使某些命令更快,因为它们被设计为在 wal_level 最小时根本不写入 WAL。(他们可以通过在最后执行 fsync 比编写 WAL 更便宜地保证崩溃安全。)

特别注意的是,如果您返回到您的

CREATE TABLE t1 (like t2);
Run Code Online (Sandbox Code Playgroud)

相反,做

CREATE TABLE UNLOGGED t1 (like t2);
Run Code Online (Sandbox Code Playgroud)

还会更快。但是,不要这样做,因为您会丢失 WAL。有关此内容的更多信息,请阅读