Pavel Luzanov:PostgreSQL 19:2026-03 CommitFest 第 5.4 部分(SQL、DEV1 与 DEV2)

Pavel Luzanov:PostgreSQL 19:2026-03 CommitFest 第 5.4 部分(SQL、DEV1 与 DEV2)

💡 原文英文,约1600词,阅读约需6分钟。
📝

内容提要

PostgreSQL 19 的 SQL 与开发更新包括:新增 ON CONFLICT DO SELECT,冲突时返回已有行;COPY 支持 on_error set_null 及含 FORCE_ARRAY 的 JSON 导出;jsonpath 增加 lower、upper、replace 等字符串方法;修复 IS JSON 对域类型的支持;postgres_fdw 传递 READ ONLY 和 DEFERRABLE 模式;允许将 CHECK 约束改为 ENFORCED,并修改带约束的虚拟生成列表达式;新增 uuid 与 bytea 直接转换及 base32hex 编码;PL/pgSQL 简单表达式绕过 SPI;新增 tid_block、tid_offset 函数;默认 TOAST 压缩改为 lz4。

🔎

延伸解读

ON CONFLICT DO SELECT 减少应用层竞态

新增的 ON CONFLICT DO SELECT 让 INSERT 在冲突时通过 RETURNING 返回已有行,避免先检查插入状态再单独 SELECT 的两步操作。文章指出,两步之间另一事务可能删除或修改该行,因此新语法不仅少一次查询,也消除了这一竞态窗口。还可配合锁定子句和 WHERE 条件控制返回与锁定行为,适合需要“插入或取回”语义的场景。

COPY 的 JSON 导出与容错加载各有边界

COPY TO 现在支持 json 格式,并可用 FORCE_ARRAY 将结果包成数组,但该格式仅用于导出,不支持 COPY FROM,也不兼容 HEADER、DELIMITER、FORCE_QUOTE 等选项。加载侧新增 on_error set_null,可把类型转换失败的值置为 NULL 并继续加载,但 NOT NULL 约束仍会生效,若置空后违反约束则命令报错。使用时需区分导出与加载的能力差异。

postgres_fdw 模式传递带来兼容性变化

此前 postgres_fdw 在外部服务器上开启的远程事务不继承本地事务的 READ ONLY 和 DEFERRABLE 模式,导致只读本地事务仍可能通过函数修改远端数据,或 DEFERRABLE 事务因远端序列化失败而中止。新版本会把这些模式传递给远端。文章明确这是不兼容变更:若应用在 READ ONLY 事务中通过 postgres_fdw 修改数据,需要改为声明 READ WRITE。

约束与生成列的可维护性提升

CHECK 约束现在可以从 NOT ENFORCED 改为 ENFORCED,执行时会扫描表验证现有行是否满足约束,无需删除重建。带 CHECK 约束的虚拟生成列也允许用 ALTER COLUMN SET EXPRESSION 修改生成表达式,表不会被重写,只扫描以重新验证约束。这两项改动降低了调整约束和生成列定义时的运维成本,但启用或修改时仍需考虑扫描带来的开销。

❓

Q&A

PostgreSQL 19 中 ON CONFLICT DO SELECT 有什么作用?

ON CONFLICT DO SELECT 在 INSERT 发生冲突时,通过 RETURNING 返回已存在的冲突行,而不是什么都不返回。它支持在 SELECT 后指定锁定子句(如 FOR UPDATE、FOR SHARE)和 WHERE 条件;不满足 WHERE 条件的冲突行不会被返回,但如果指定了锁定子句,该行仍会被锁定。

COPY 命令在 PostgreSQL 19 中支持哪些新格式和错误处理选项?

COPY 新增 json 导出格式(仅 COPY TO 支持),并可用 FORCE_ARRAY 将输出包装为数组。错误处理方面,新增 on_error set_null 选项,可将数据类型转换错误的行中无效值替换为 NULL 后仍加载该行,但 NOT NULL 约束(包括域上的)仍会强制执行,若 NULL 落入此类列则命令失败。

PostgreSQL 19 的 jsonpath 增加了哪些字符串方法?

jsonpath 新增 lower()、upper()、initcap()、replace()、split_part(),以及 btrim()、ltrim()、rtrim() 等字符串方法。

postgres_fdw 在 PostgreSQL 19 中关于事务模式有什么变化?

postgres_fdw 现在会将本地事务的 READ ONLY 和 DEFERRABLE 模式传递给外部服务器上打开的远程事务。此前远程事务不继承这些模式,可能导致 READ ONLY 本地事务仍能修改外部数据,或 DEFERRABLE 事务因外部序列化失败而中止。此变更不兼容旧版本:若应用通过 postgres_fdw 在 READ ONLY 事务中修改数据,需改为声明 READ WRITE。

PostgreSQL 19 中如何将 CHECK 约束从 NOT ENFORCED 改为 ENFORCED?

使用 ALTER TABLE ... ALTER CONSTRAINT ... ENFORCED 即可,例如 ALTER TABLE test ALTER CONSTRAINT check_id ENFORCED;。设置时表会被扫描以验证现有行满足约束。版本 18 不允许这样修改,必须删除并重建约束。

PostgreSQL 19 中 uuid 和 bytea 之间如何转换?base32hex 编码有什么好处?

现在支持 uuid 与 bytea 之间的显式转换,无需再经过文本表示。encode/decode 函数新增 base32hex 格式,适合 UUIDv7:生成的字符串比十六进制表示更短,且在 C 排序规则下保持排序顺序。转换为 base32hex 时 UUID 值右侧会用“=”填充,可用 rtrim 去除填充,因为 decode 接受带或不带填充的 base32hex 输入。

PostgreSQL 19 中 PL/pgSQL 的简单表达式赋值有什么性能改进?

对于不访问表的简单表达式,如果结果赋值给单个变量,PL/pgSQL 现在直接求值,不再通过 SPI 执行完整查询,从而避免 SPI 开销。副作用是这类表达式不再出现在 pg_stat_statements 中。

PostgreSQL 19 新增的 tid_block 和 tid_offset 函数是做什么的?

这两个函数直接从 ctid 值中提取块号和块内偏移量,无需像以前那样先转换为 text 再转换为 point。例如 SELECT ctid, tid_block(ctid), tid_offset(ctid) FROM bookings LIMIT 1;。

PostgreSQL 19 的默认 TOAST 压缩方法是什么?

如果服务器编译时支持 lz4,则默认 TOAST 压缩方法变为 lz4。此前默认使用 pglz,而 lz4 在压缩率和 CPU 使用方面更高效。可通过 \dconfig default_toast_compression 查看。

🏷️

标签

➡️

继续阅读