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及以上)
背景
Access Method(AM)负责定义和实现PostgreSQL中表和索引的存储方式。执行器只需要将数据行或索引行分别传递给Table AM和Index AM即可,无需关注AM内部如何实现。
在PostgreSQL 12及后续版本引入了可扩展的Table AM,目前仅内置支持Heap AM。Heap AM支持以下两种接口定义:
然而,当需要插入的元组数量较多时,单行插入的算法效率远低于批量插入。但由于批量数据插入涉及批量暂存元组,还需要完整的生命周期控制。
针对上述问题,PolarDB PostgreSQL版扩展了新的可选Table AM接口,并为Heap AM实现该接口。新的Table AM接口完成了以下优化:
实现对批量插入完整的生命周期控制。
在Heap AM内使用更加高效的插入算法和WAL日志格式。
由此,其余可能插入多行数据的语法也可以通过这套Table AM接口使用批量插入能力。Heap AM的单行插入接口和批量插入接口同时支持堆表的逻辑复制。
使用说明
目前支持使用批量插入Table AM的语法如下:
当前语法使用批量插入接口wal_level
参数值有关,当该值为logical
时,以上语法默认使用批量插入接口,当该参数为其他值则使用批量导入基础设施优化批量导入操作。
原理介绍
Buffer层算法
单行插入算法
具体步骤如下:
填充元组信息。
计算该元组需要的空闲空间。
找到一个能够容纳当前插入的元组的页面。
对页面上锁,并将元组放入页面中。
标记页面为脏页。
产生一条WAL日志记录当前页面修改。
释放页面锁。
批量插入算法
具体步骤如下:
在内存中暂存一批元组。
批量填充元组信息。
找到一个能够容纳当前插入元组的页面。
对页面上锁,将元组放入页面中。
如果页面空间充足,则继续放入元组,直到页面空间不足或暂存元组耗尽。
标记页面为脏页。
产生一条WAL日志记录当前页面修改。
释放页面锁。
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)