本文介绍了堆表预读、堆表预扩展以及索引创建预扩展的简介、原理以及使用方法等。

前提条件

支持的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索引。其他索引类型暂不支持。

原理介绍

  • 堆表预读
    堆表预读的实现步骤主要分为以下四步:
    1. 在Buffer Pool中申请N个Buffer。
    2. 通过palloc在内存中申请一段大小为N*页大小的空间,简称为p
    3. 通过PFS批量读取堆表中N * 页大小的数据拷贝至p中。
    4. p中N个页的内容逐个拷贝至从Buffer Pool申请的N个Buffer中。
    后续的读取操作会直接命中Buffer。数据流图如下所示:堆表预读
  • 堆表预扩展
    预扩展的实现步骤主要分为以下三步:
    1. 从Buffer Pool中申请N个Buffer,不触发文件系统的页扩展。
    2. 通过PFS的文件写入接口进行批量页扩展,并且写入为全零页。
    3. 对申请出来的页逐个进行页初始化,标识页的可用空间,结束预扩展。
  • 索引创建预扩展
    索引创建预扩展的实现步骤与预扩展类似,但没有涉及Buffer的申请。步骤如下:
    1. 写索引页时,通过PFS的文件写入接口进行批量页扩展,并且写入为全零页。
    2. 将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性能对比如下所示:vacuum性能对比
    • 400 GB表的SeqScan性能对比如下所示:seqscan性能对比
    结论:
    • 堆表预读在Vacuum和SeqScan场景下性能提升了1-2倍。
    • 堆表预读大小在超过默认值128 KB之后对性能提升没有明显帮助。
  • 堆表预扩展
    400 GB表数据装载性能对比如下所示:数据装载性能对比
    结论:
    • 堆表预扩展在数据装载场景下带来一倍的性能提升。
    • 堆表预扩展大小在超过默认值4 MB后对性能没有明显帮助。
  • 索引创建预扩展
    400 GB表创建索引性能对比如下所示:创建索引性能对比
    结论:
    • 索引创建预扩展在索引创建场景下能够带来30%的性能提升。
    • 索引创建预扩展大小超过默认值4 MB对性能没有明显帮助。