跳转到主要内容

2 PostgreSQL 17 新特性

PostgreSQL 17 的主要更新,包括 SQL/JSON、复制、清理、增量备份、查询规划和监控。

Web 版说明。本章包含几处源文错误和需要补充的版本限定。阅读下方正文时,请同时参阅 PostgreSQL 17 勘误。

如果你熟悉 PostgreSQL 的早期版本,本章可以帮助你了解过去一年里发生了哪些变化。这里仅介绍部分更新;完整变更列表请参阅发行说明:postgrespro.com/docs/postgresql/17/release-17. 你也可以关注我们的博客,了解最新动态:https://habr.com/en/companies/postgrespro/articles/.

SQL 命令

改进了 MERGE 命令。 新增的 WHEN NOT MATCHED BY SOURCE 子句可以处理目标关系中存在、源关系中不存在的行。现在还支持 RETURNING 子句,也可以像使用表一样将视图用作目标。

借助新增的 on_error 参数,现在可以让 COPY FROM 命令忽略某些列中值的格式无效所引发的错误。log_verbosity 参数则会以 NOTICE 级别的消息显示被跳过的值。未来的改进可能会允许将无效值放入单独的表中。

现在可以修改表中的生成表达式,方法是在 ALTER COLUMN 命令中使用 SET EXPRESSION 子句。此前,只能删除该表达式。

现在可以按照 SQL 标准,使用表示当前时区的简写 AT LOCAL,替代带有时区值的 AT TIME ZONE。

函数与类型

重载后的 random 函数现在接受两个参数,分别指定随机数的最小值和最大值。支持 int、bigint 和 numeric 值。

interval 类型现在支持无穷值。

除了用于十六进制的 to_hex,还增加了类似的函数,分别用于二进制(to_bin)和八进制(to_oct)。

为 to_timestamp 函数新增了格式模板: TZ(时区)和 OF(相对于 UTC 的偏移)。此前,必须使用 to_char。

SQL 标准定义的 xmltext 函数将输入字符串转换为 XML,并正确转义特殊字符。

新增 Unicode 函数: unicode_assigned 检查字符串中的每个字符是否都有有效的 Unicode 值,unicode_version 返回 PostgreSQL 的 Unicode 版本,而 icu_unicode_version 返回 ICU 版本。

现在,一些带有多个参数的聚合函数已在定义中为参数指定了名称。

SQL/JSON

实现 SQL/JSON 2016 标准的这部壮丽史诗,如今终于落幕。 此前缺少的 JSON_EXISTS、JSON_QUERY、JSON_VALUE 和 JSON_TABLE 函数终于全部到位。jsonpath 语言也增加了新的数据转换方法,可以将数据转换为 bigint、boolean、date、decimal、integer、number、string、time_tz、time、timestamp_tz 和 timestamp。

逻辑复制

升级现在容易多了。 pg_upgrade 工具会将复制槽迁移到发布端,订阅端只需更新连接字符串。升级订阅端时,所有订阅都会完整保留,复制可以继续,无需重新同步。

逻辑副本可以基于物理副本创建:物理副本的所有表都已同步,因此配置复制不会花费太多时间。新工具 pg_createsubscriber 会将物理副本切换到读写模式,在两台服务器的一个或多个数据库中创建成对的发布端和订阅端,并在订阅属性中指定继续复制的起始位置。

逻辑复制槽会迁移到副本上,并持续更新。完成计划内切换后,只需更新连接字符串,使其指向新的服务器,复制即可恢复。

通过 pg_stat_subscription 视图新增的 worker_type 列,可以查看复制工作进程正在做什么。

可能的值有:apply、parallel apply 和 table synchronization。

pg_stat_replication 视图中的 conflicting 和 invalidation_reason 列,会显示逻辑复制槽是否失效,以及失效的原因。

此外,针对存在大量子事务的情况,逻辑解码以及依赖它的逻辑复制都得到了显著优化。

清理

借助基于基数树的新死元组存储方式,清理现在需要的内存大幅减少。此外,元组 ID 查找速度更快,内存改为动态分配(此前会一次性分配全部 maintenance_work_mem),1 GB 的硬性上限也已取消。现在,大多数表只需一轮就能完成清理,避免反复扫描索引。

清理监控得到改进。 pg_stat_progress_vacuum 新增了两列:待清理的索引总数(indexes_total),以及已清理的索引数量(indexes_processed)。

如果在清理过程中冻结行,产生的 WAL 现在更少了。这两个操作会合并为一条 WAL 记录。

备份与升级

PostgreSQL 新增了页级增量备份。walsummarizer 进程(配合 summarize_wal 参数)读取 WAL,记录哪些页被修改。pg_basebackup 工具新增的 --incremental 参数可启用增量备份,并利用复制协议的新特性。恢复工具 pg_combinebackup 会将增量备份及其依赖的所有备份合并为完整备份。

在 pg_basebackup 和 pg_receivewal 中,可以通过 dbname 参数指定要连接的数据库。前者使用 -R 选项时,还会在写入 postgresql.auto.conf 时将数据库名添加到 primary_conninfo 中。这两个工具本身都不需要数据库名,但通过代理连接,以及在副本上配置复制槽同步时,都需要提供它。

为 pg_dump 新增了选项: --filter 指定一个文件,其中列出要纳入转储或从转储中排除的对象。--exclude-extension 则排除一组扩展。

对于含有多个大对象和表的数据库,使用 pg_upgrade 升级更快了。pg_dump 现在会在备份索引中对大对象进行分组,而 pg_restore 则按 --transaction-size 指定的事务大小提交更改。此外,并行恢复中主导进程的逻辑也得到了改进。

访问控制

新增权限 MAINTAIN,用于 ANALYZE、VACUUM(包括 VACUUM FULL)、CLUSTER、REINDEX、REFRESH MATERIALIZED VIEW 和 LOCK TABLE。加入 pg_maintain 角色后,即可对数据库中的每个关系拥有这项权限。

使用 libpq 的客户端应用程序现在可以通过 TLS 直接连接。将 sslnegotiation 参数设置为 requiredirect 即可启用。

新的默认权限显示方式: 如果没有权限,psql 会返回 (none),同时也会遵循 \pset null 的设置。

查询规划与执行

规划器现在可以使用物化 CTE 的统计信息,包括 CTE 的列统计信息和行排序顺序。

规划器可以交换 GROUP BY 中的表,例如借此利用索引或增量排序。

包含子事务的函数现在是 PARALLEL SAFE 的。 这尤其包括带有 EXCEPTION 块的 PL/pgSQL 函数。此外,计划的并行部分现在也可以包含 InitPlan 节点。

EXPLAIN 命令的改进:

  • memory 参数显示生成计划时使用了多少内存。

  • serialize 参数显示将查询结果转换为文本或二进制格式、以便发送给客户端的代价(尤其是 TOAST 数据的重组)。

  • SubPlan 和 InitPlan 节点的可读性得到改进。

许多索引特性过去一直仅适用于 B-树。现在,其他类型的索引也可以使用这些特性:

  • 哈希索引可用于识别逻辑复制订阅端被修改的行。

  • 增量排序可以配合 GiST 和 SP-GiST 索引使用。

  • BRIN 索引可以并行创建。

分区方面的一些改进:

  • 现在可以设置排他约束。

  • 完整支持 GENERATED AS IDENTITY 列。

监控

新视图 pg_stat_checkpointer 显示检查点进程的统计信息,这些信息此前由 pg_stat_bgwriter 提供。它还会显示副本重启点的统计信息。pg_stat_bgwriter 中的 buffers_backend 和 buffers_backend_fsync 列已移除,因为 pg_stat_io 现在能够提供更准确的进程数据。

pg_stat_statements 视图:

  • 新增列,用于跟踪全部统计信息的重置时间和最短、最长耗时统计信息的重置时间(stats_since 和 minmax_stats_since)。

  • 归一化命令 CALL、PREPARE TRANSACTION、COMMIT/ROLLBACK PREPARED 和 DEALLOCATE:将它们的参数替换为常量值,从而将这些命令作为单个事件记录。

现在可以在 pg_stats 中查看范围类型列的统计信息。

扩展开发者现在可以定义自己的等待事件。dblink 和 postgres_fdw 扩展的开发者率先使用了这项功能。

除了文档之外,现在也可以在新视图 pg_wait_events 中查看等待事件的类型和描述。

事件触发器

终于可以为数据库连接事件创建 ON LOGIN 触发器了。

事件触发器支持 REINDEX 命令。

event_triggers 参数用于启用或禁用事件触发器,主要用于调试。

配置参数

由于实现与效率方面出现了问题,最初在 PostgreSQL 9.6 中引入的参数 old_snapshot_threshold 已被移除。

新参数 transaction_timeout 限制事务的总时长。 过去的 statement_timeout 和 idle_in_transaction_session_timeout 参数无法保证事务在指定时间内完成或终止。

当 huge_pages = try 时,huge_pages_status 参数会显示是否分配了大页。

一些新增配置参数用于设置 SLRU 缓存大小,以便进行更细致的调优:

  • commit_timestamp_buffers —— 提交时间;

  • multixact_member_buffers 和 multixact_offset_buffers —— 多事务(multitransaction,MultiXact);

  • subtransaction_buffers —— 嵌套事务;

  • notify_buffers —— 异步消息;

  • transaction_buffers —— 事务状态;

  • serializable_buffers —— 可串行化事务冲突。

ALTER SYSTEM 命令现在可以将自定义参数写入 postgresql.auto.conf。allow_alter_system 参数可以阻止 ALTER SYSTEM 意外修改配置。

本地化

新增内置提供者,支持 C 和 C.UTF8 区域设置。

其他

对于某些工具,可以用 --synch-method 选项设置磁盘同步方法,包括 initdb、pg_basebackup、pg_checksums、pg_rewind、pg_upgrade 和 pg_dump。默认方法是 fsync。

walsender 进程会尽可能直接从缓冲区读取 WAL 记录,绕过文件系统。

此前,PostgreSQL 为每个页单独发起一次系统调用,并寄望于操作系统将这些操作合并。现在,有了多块读取基础设施:可以一次读取一系列页(每次最多 io_combine_limit 字节)。未来还将加入异步读取,在页到达时就开始处理,而无需等待整个操作完成。