Dimitri Fontaine:为 PostgreSQL 19 做好准备

Dimitri Fontaine:为 PostgreSQL 19 做好准备

💡 原文英文,约5500词,阅读约需20分钟。
📝

内容提要

PostgreSQL 19 Beta 3 发布,新增多项 SQL 改进:支持 FOR PORTION OF 进行时间区间更新、INSERT ON CONFLICT DO SELECT 简化冲突处理、窗口函数支持 IGNORE NULLS、CHECK 约束可动态切换强制,以及 REPACK 替代 VACUUM FULL。但 MERGE PARTITIONS 因设计缺陷被回退。此外还有 DDL 目录函数、范围减法、随机日期函数及 SQL/PGQ 图查询等新特性。

🔎

延伸解读

升级前必读:兼容性破坏项

PostgreSQL 19 包含多项可能影响现有系统的兼容性变更。JIT 默认关闭,依赖自动 JIT 的大型分析查询需手动开启。standard_conforming_strings 强制开启,旧版本 pg_dump 导出的数据可能无法加载。RADIUS 认证被移除,MD5 密码认证将发出警告,建议迁移至 scram-sha-256。inet/cidr 的 GiST 索引默认操作符类变更,pg_upgrade 会拒绝升级,需先 REINDEX。max_locks_per_transaction 默认值翻倍,但实际容

MERGE PARTITIONS 被回退的启示

MERGE PARTITIONS 因设计缺陷在发布前一个月被回退,这并非失败,而是 PostgreSQL 开发流程的体现。Beta 3 中该功能存在五个问题:CHECK 约束静默丢失、生成列被重新计算、逻辑复制出现虚假插入、发布可能清空自身等。这些问题都关乎分区携带的元数据,而非行移动本身。回退意味着功能将在语义完善后重新引入,届时会更可靠。用户应关注实际运行的版本,而非仅依赖发布说明。

SQL/PGQ 图查询:当前能力与局限

PostgreSQL 19 实现了 SQL/PGQ 标准,允许在现有关系表上声明属性图并进行模式匹配查询。但当前仅支持固定长度的边模式,可变长度路径(如 1 到 4 跳)尚未实现,错误提示明确说明该功能未支持。对于可达性、最短路径等查询,仍需使用 WITH RECURSIVE。尽管如此,已实现的部分包括系统目录、解析器、权限检查等基础架构,为未来扩展奠定基础。

新 SQL 功能的实际应用场景

FOR PORTION OF 简化了时间区间数据的更新和删除,自动拆分区间,避免手动操作。INSERT ... ON CONFLICT DO SELECT 解决了 upsert 后需单独查询的问题,适用于幂等写入场景。窗口函数 IGNORE NULLS 可跳过 NULL 值,获取最近的非空值,如计算上次完赛名次。CHECK 约束可动态切换强制,但需注意与 NOT VALID 的区别。REPACK 统一了 VACUUM FULL 和 CLUSTER,并提供 CONCURRENTLY 选项,但有限制条件。

❓

Q&A

PostgreSQL 19 中 FOR PORTION OF 子句有什么用途?

FOR PORTION OF 用于对时间区间(如 daterange)进行部分更新或删除,自动将区间拆分为多个行,避免手动编写 UPDATE 和 INSERT 语句。例如,可以将合同的有效期从中间某段改为新值,原行会缩小,新行会插入,且不会重叠。

PostgreSQL 19 中 INSERT ... ON CONFLICT DO SELECT 解决了什么问题?

它解决了在冲突时无法直接返回现有行的问题。以前需要先执行 INSERT ... ON CONFLICT DO NOTHING 或 DO UPDATE,再单独 SELECT。现在 DO SELECT 可以直接返回冲突行,并支持 FOR UPDATE 等锁选项和 WHERE 过滤,但必须使用 RETURNING。

PostgreSQL 19 中窗口函数 IGNORE NULLS 有什么作用?

IGNORE NULLS 允许 lead(), lag(), first_value(), last_value(), nth_value() 等窗口函数跳过 NULL 值,返回最近的非 NULL 值。例如,在赛车数据中,某场比赛未完成(NULL),使用 IGNORE NULLS 可以获取上一次实际完赛的名次。

PostgreSQL 19 中如何动态启用或禁用 CHECK 约束?

可以使用 ALTER TABLE ... ALTER CONSTRAINT ... [NOT] ENFORCED 来切换 CHECK 约束的强制状态。禁用后,新数据不会检查约束;重新启用时,会验证现有数据,若有违反则报错。这与 NOT VALID 不同,NOT VALID 只对新行生效,而 NOT ENFORCED 完全不检查。

PostgreSQL 19 中 REPACK 命令与 VACUUM FULL 有何区别?

REPACK 是 PG 19 中统一 VACUUM FULL 和 CLUSTER 的新命令,用于重写表以回收空间或应用物理排序。它支持 CONCURRENTLY 选项,避免长时间持有 ACCESS EXCLUSIVE 锁,但有一些限制,如不适用于无主键的表、非 MVCC 安全等。

为什么 PostgreSQL 19 回退了 MERGE PARTITIONS 功能?

MERGE PARTITIONS 因存在多个设计问题而被回退,包括 CHECK 约束被静默丢弃、生成列被重新计算、逻辑复制产生虚假插入、发布可能变空等。这些问题在 Beta 3 中可复现,因此决定推迟到后续版本,以确保语义正确。

PostgreSQL 19 中新增了哪些 DDL 目录函数?

新增了 pg_get_role_ddl(), pg_get_tablespace_ddl(), pg_get_database_ddl() 三个函数,可以直接从系统目录生成对象的 CREATE/ALTER 语句,无需外部工具。它们返回一组文本,按执行顺序排列,并支持 pretty 等选项。

PostgreSQL 19 中 range_minus_multi() 函数有什么用途?

range_minus_multi() 用于从一个范围中减去另一个范围,当减去的范围位于中间时,会返回多个剩余片段(作为一组行),而普通的范围减法会报错。例如,从 [2007-01-01, 2013-01-01) 中减去 [2010-01-01, 2011-01-01) 会得到两个范围。

PostgreSQL 19 中 random() 函数新增了哪些类型支持?

random() 新增了对 date、timestamp 和 timestamptz 的支持,可以生成指定范围内的随机日期或时间戳,边界包含。例如,random('2017-03-26'::date, '2017-11-26'::date) 会生成该日期范围内的随机日期。

PostgreSQL 19 中 SQL/PGQ 支持哪些图查询功能?

SQL/PGQ 允许在现有关系表上定义属性图(CREATE PROPERTY GRAPH),并使用 GRAPH_TABLE 进行模式匹配查询。目前支持固定长度的路径模式,但不支持可变长度路径(如量词 {1,4}),后者将在未来版本中实现。

🏷️

标签

➡️

继续阅读