本文介绍了堆表预读、堆表预扩展以及索引创建预扩展的简介、原理以及使用方法等。
前提条件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 14(内核小版本14.5.1.0及以上)
PostgreSQL 11(内核小版本1.1.1及以上)
您可通过如下语句查看PolarDB PostgreSQL版的内核小版本的版本号:
PostgreSQL 14
select version();
PostgreSQL 11
show polar_version;
背景信息
PolarDB PostgreSQL版底层使用PolarFS(以下简称为PFS)作为文件系统。不同于 ext4 等单机文件系统,PFS在页扩展过程中,元数据更新开销较大。且PFS的最小页扩展粒度为4 MB。而PostgreSQL 8 KB的页扩展粒度并不适合PFS,将会导致写表或创建索引时性能下降。同时,PFS在读取大块页面时I/O效率更高。
为了适配上述特征,PolarDB PostgreSQL版设计了堆表预读、堆表预扩展、索引创建预扩展的功能,使运行在PFS上的PolarDB PostgreSQL版能够获得更好的性能。
简介
堆表预读
在PostgreSQL读取堆表的过程中,会以8 KB页为单位通过文件系统读取页面至内存缓冲池(Buffer Pool)中。PFS对于这种数据量较小的I/O操作并不是特别高效。因此,PolarDB PostgreSQL版为了适配PFS而设计了堆表批量预读。
当读取的页数量大于1时,将会触发批量预读,一次I/O读取128 KB数据至缓冲池中。预读对顺序扫描(Sequential Scan)、Vacuum两种场景性能可以带来一倍左右的提升,在索引创建场景下可以带来18%的性能提升。
堆表预扩展
在PostgreSQL中,表空间的扩展过程中将会逐个申请并扩展8 KB的页。即使是PostgreSQL支持的批量页扩展,进行一次N页扩展的流程中也包含了N次I/O操作。这种页扩展不符合PFS最小页扩展粒度为4 MB的特性。因此,PolarDB PostgreSQL版设计了堆表批量预扩展。
在扩展堆表的过程中,一次I/O扩展4 MB页。在写表频繁的场景下(例如装载数据),能够带来一倍的性能提升。
索引创建预扩展
索引创建预扩展与堆表预扩展的功能类似。索引创建预扩展特别针对PFS优化索引创建过程。在索引创建的页扩展过程中,一次I/O扩展4 MB页。这种设计可以在创建索引的过程中带来30%的性能提升。
说明当前索引创建预扩展只适配了B-Tree索引。其他索引类型暂不支持。
原理介绍
堆表预读
堆表预读的实现步骤主要分为以下四步:
在Buffer Pool中申请N个Buffer。
通过
palloc
在内存中申请一段大小为N*页大小
的空间,简称为p
。通过PFS批量读取堆表中
N * 页大小
的数据拷贝至p
中。将
p
中N个页的内容逐个拷贝至从Buffer Pool申请的N个Buffer中。
后续的读取操作会直接命中Buffer。数据流图如下所示:
堆表预扩展
预扩展的实现步骤主要分为以下三步:
从Buffer Pool中申请N个Buffer,不触发文件系统的页扩展。
通过PFS的文件写入接口进行批量页扩展,并且写入为全零页。
对申请出来的页逐个进行页初始化,标识页的可用空间,结束预扩展。
索引创建预扩展
索引创建预扩展的实现步骤与预扩展类似,但没有涉及Buffer的申请。步骤如下:
写索引页时,通过PFS的文件写入接口进行批量页扩展,并且写入为全零页。
将Buffer Pool中已经构建好的索引页写入文件系统中。
使用指南
堆表预读
堆表预读的参数名为
polar_bulk_read_size
,功能默认开启,默认大小为128 KB。说明不建议用户自行修改该参数,128 KB是贴合PFS的最优值,自行调整并不会带来性能的提升。
关闭堆表预读功能。
ALTER SYSTEM SET polar_bulk_read_size = 0; SELECT pg_reload_conf();
开启堆表预读功能并设置预读大小为128 KB。
ALTER SYSTEM SET polar_bulk_read_size = '128 KB'; SELECT pg_reload_conf();
堆表预扩展
堆表预扩展的参数名为
polar_bulk_extend_size
,功能默认开启,预扩展的大小默认是4 MB。说明不建议用户自行修改该参数值,4 MB是贴合PFS的最优值。
关闭堆表预扩展功能。
ALTER SYSTEM SET polar_bulk_extend_size = 0; SELECT pg_reload_conf();
开启堆表预扩展功能并设置预扩展大小为4 MB。
ALTER SYSTEM SET polar_bulk_extend_size = '4 MB'; SELECT pg_reload_conf();
索引创建预扩展
索引创建预扩展的参数名为
polar_index_create_bulk_extend_size
,功能默认开启。索引创建预扩展的大小默认是4 MB。说明不建议用户自行修改该参数值,4 MB是贴合PFS的最优值。
关闭索引创建预扩展功能。
ALTER SYSTEM SET polar_index_create_bulk_extend_size = 0; SELECT pg_reload_conf();
开启索引创建预扩展功能并设置预扩展大小为4 MB。
ALTER SYSTEM SET polar_index_create_bulk_extend_size = '4 MB'; SELECT pg_reload_conf();
性能对比
为了展示堆表预读、堆表预扩展、索引创建预扩展的性能提升效果,在PostgreSQL 14版本的PolarDB PostgreSQL版集群上进行了测试。
规格:8核32 GB内存。
测试场景:400 GB pgbench测试。
堆表预读
400 GB表的Vacuum性能对比如下所示:
400 GB表的SeqScan性能对比如下所示:
结论:
堆表预读在Vacuum和SeqScan场景下性能提升了1-2倍。
堆表预读大小在超过默认值128 KB之后对性能提升没有明显帮助。
堆表预扩展
400 GB表数据装载性能对比如下所示:
结论:
堆表预扩展在数据装载场景下带来一倍的性能提升。
堆表预扩展大小在超过默认值4 MB后对性能没有明显帮助。
索引创建预扩展
400 GB表创建索引性能对比如下所示:
结论:
索引创建预扩展在索引创建场景下能够带来30%的性能提升。
索引创建预扩展大小超过默认值4 MB对性能没有明显帮助。