# PostgreSQL 17 新特性

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

---

LLMS 索引： [llms.txt](/llms.txt)

---

<blockquote class="intro-editorial-note">
<p><strong>Web 版说明。</strong>本章包含几处源文错误和需要补充的版本限定。阅读下方正文时，请同时参阅 <a href="/#errata">PostgreSQL 17 勘误</a>。</p>
</blockquote>


<span id="intro-chapter-2" class="pdf-anchor"></span><span id="intro-page-16" class="pdf-anchor"></span>

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

## SQL 命令 {#intro-section-2-1}

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

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

<span id="intro-page-17" class="pdf-anchor"></span>

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

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

## 函数与类型 {#intro-section-2-2}

重载后的 `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 版本。

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

<span id="intro-page-18" class="pdf-anchor"></span>

## SQL/JSON {#intro-section-2-3}

**实现 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`。

## 逻辑复制 {#intro-section-2-4}

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

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

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

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

<span id="intro-page-19" class="pdf-anchor"></span>

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

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

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

## 清理 {#intro-section-2-5}

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

**清理监控得到改进。** `pg_stat_progress_vacuum` 新增了两列：待清理的索引总数（`indexes_total`），以及已清理的索引数量（`indexes_processed`）。

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

## 备份与升级 {#intro-section-2-6}

PostgreSQL 新增了页级**增量备份**。`walsummarizer` 进程（配合 `summarize_wal` 参数）读取 WAL，记录哪些页<span id="intro-page-20" class="pdf-anchor"></span>被修改。`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` 指定的事务大小提交更改。此外，并行恢复中主导进程的逻辑也得到了改进。

## 访问控制 {#intro-section-2-7}

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

<span id="intro-page-21" class="pdf-anchor"></span>

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

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

## 查询规划与执行 {#intro-section-2-8}

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

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

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

`EXPLAIN` 命令的改进：

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

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

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

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

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

<span id="intro-page-22" class="pdf-anchor"></span>

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

- BRIN 索引可以**并行**创建。

分区方面的一些改进：

- 现在可以设置**排他约束**。

- 完整支持 `GENERATED AS IDENTITY` **列**。

## 监控 {#intro-section-2-9}

新视图 `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` 中查看**等待事件的类型和描述**。

<span id="intro-page-23" class="pdf-anchor"></span>

## 事件触发器 {#intro-section-2-10}

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

事件触发器**支持 REINDEX 命令**。

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

## 配置参数 {#intro-section-2-11}

由于实现与效率方面出现了问题，最初在 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` —— 异步消息；

<span id="intro-page-24" class="pdf-anchor"></span>

- `transaction_buffers` —— 事务状态；

- `serializable_buffers` —— 可串行化事务冲突。

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

## 本地化 {#intro-section-2-12}

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

## 其他 {#intro-section-2-13}

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

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

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

<span id="intro-page-25" class="pdf-anchor"></span>
