Multi-Insert Table AM基础设施

PolarDB PostgreSQL集群Table AM的接口定义中包含单行插入接口和批量插入接口,当需要插入较多元组数据时,可通过启用批量插入接口提高数据插入效率。

前提条件

支持的PolarDB PostgreSQL的版本如下:

  • PostgreSQL 16(内核小版本2.0.16.8.3.0及以上)

  • PostgreSQL 15(内核小版本2.0.15.12.4.0及以上)

  • PostgreSQL 14(内核小版本2.0.14.13.28.0及以上)

说明

您可在控制台查看内核小版本号,也可以通过SHOW polardb_version;语句查看。如未满足内核小版本要求,请升级内核小版本

背景

Access Method(AM)负责定义和实现PostgreSQL中表和索引的存储方式。执行器只需要将数据行或索引行分别传递给Table AMIndex AM即可,无需关注AM内部如何实现。

PostgreSQL 12及后续版本引入了可扩展的Table AM,目前仅内置支持Heap AM。Heap AM支持以下两种接口定义:

  • 批量插入接口:一次性处理多行数据,仅支持COPY FROM语法。

  • 单行插入接口:每次处理一行数据,适用于除COPY FROM语法之外的其他涉及对表插入数据的语法。

然而,当需要插入的元组数量较多时,单行插入的算法效率远低于批量插入。但由于批量数据插入涉及批量暂存元组,还需要完整的生命周期控制。

针对上述问题,PolarDB PostgreSQL扩展了新的可选Table AM接口,并为Heap AM实现该接口。新的Table AM接口完成了以下优化:

  • 实现对批量插入完整的生命周期控制。

  • Heap AM内使用更加高效的插入算法和WAL日志格式。

由此,其余可能插入多行数据的语法也可以通过这套Table AM接口使用批量插入能力。Heap AM的单行插入接口和批量插入接口同时支持堆表的逻辑复制。

使用说明

目前支持使用批量插入Table AM的语法如下:

说明

当前语法使用批量插入接口wal_level参数值有关,当该值为logical时,以上语法默认使用批量插入接口,当该参数为其他值则使用批量导入基础设施优化批量导入操作。

原理介绍

Buffer层算法

单行插入算法

具体步骤如下:

  1. 填充元组信息。

  2. 计算该元组需要的空闲空间。

  3. 找到一个能够容纳当前插入的元组的页面。

  4. 对页面上锁,并将元组放入页面中。

  5. 标记页面为脏页。

  6. 产生一条WAL日志记录当前页面修改。

  7. 释放页面锁。

批量插入算法

具体步骤如下:

  1. 在内存中暂存一批元组。

  2. 批量填充元组信息。

  3. 找到一个能够容纳当前插入元组的页面。

  4. 对页面上锁,将元组放入页面中。

  5. 如果页面空间充足,则继续放入元组,直到页面空间不足或暂存元组耗尽。

  6. 标记页面为脏页。

  7. 产生一条WAL日志记录当前页面修改。

  8. 释放页面锁。

WAL日志格式

  • 单行插入将记录Heap INSERT类型日志:

    -[ RECORD 1 ]----+--------------------------------------------
    start_lsn        | 0/40BE24E0
    end_lsn          | 0/40BE2520
    prev_lsn         | 0/40BE24B8
    xid              | 792
    resource_manager | Heap
    record_type      | INSERT
    record_length    | 61
    main_data_length | 3
    fpi_length       | 0
    description      | off: 8, flags: 0x00
    block_ref        | blkref #0: rel 1663/5/16412 fork main blk 0
  • 批量插入将记录Heap2 MULTI_INSERT类型日志。该日志类型可以一次性记录在页面上插入的多行数据:

    -[ RECORD 1 ]----+------------------------------------------------------------------
    start_lsn        | 0/40BE2548
    end_lsn          | 0/40BE2610
    prev_lsn         | 0/40BE2520
    xid              | 793
    resource_manager | Heap2
    record_type      | MULTI_INSERT
    record_length    | 194
    main_data_length | 20
    fpi_length       | 0
    description      | ntuples: 8, flags: 0x02, offsets: [9, 10, 11, 12, 13, 14, 15, 16]
    block_ref        | blkref #0: rel 1663/5/16412 fork main blk 0

差异分析

批量插入算法能够大幅减少页面上锁频率,同时减少产生的WAL日志数量,优化日志内容紧凑性。

使用方法

参数polar_enable_tableam_multi_insert用于控制是否启用批量插入的Table AM接口,默认开启:

SHOW polar_enable_tableam_multi_insert;
 polar_enable_tableam_multi_insert
-----------------------------------
 on
(1 row)