PostgreSQL 19 Beta 值得测吗?并行 Autovacuum、REPACK 到 WAIT FOR LSN 看生产影响
前言
PostgreSQL 19 Beta 1 在 2026 年 6 月 4 日发布,正式版(GA)预计 9-10 月落地。与往年"追新特性"不同,这个版本的 200 多项变更里,真正值得关注的几乎全是运维和性能层面:autovacuum 终于支持并行了、内置了REPACK在线重建表、外键插入性能翻倍、WAIT FOR LSN解决了读写分离的"读到旧数据"问题。
但同样重要的是几个默认值变更——JIT 默认关闭、RADIUS 认证直接移除、TOAST 压缩默认换成 lz4——如果你的生产环境不做提前验证,升级时很可能踩坑。
这篇文章不罗列全部 200 项变更,而是站在后端工程师和 DBA 的角度,挑出对生产系统影响最大的变化,逐一讲清它解决了什么问题、怎么用、什么场景受益,最后给一份升级前非生产环境验证清单。
背景:Beta 1 的定位——能测,不能上
先明确版本定位:
- Beta 1 于 2026-06-04 发布,后续可能还有 Beta 2、Release Candidate。
- GA 预计 2026 年 9-10 月,在此之前 API、目录结构、行为都还可能变。
- Beta 之间不保证升级路径,不要在生产数据上测试。
- 正确做法:用一份生产数据的副本(pg_dump 恢复或克隆环境),在非生产环境跑你的真实工作负载。
核心思路:PostgreSQL 19 的生产价值在哪
一句话概括 PostgreSQL 19 的核心方向:把 DBA 每周都在跟的运维痛点——vacuum 维护窗口、表膨胀、读写分离一致性、外键插入税——用引擎层面的能力解决掉。
按影响面排序,最值得关注的五块:
| 优先级 | 特性 | 影响面 | 你的工作负载可能受益吗 |
|---|---|---|---|
| 高 | 并行 Autovacuum + 评分系统 | 所有大表 | 有大表和多索引?受益明显 |
| 高 | REPACK / REPACK CONCURRENTLY | 膨胀治理 | 用过 pg_repack?可以去掉这个依赖 |
| 高 | JIT 默认关闭 + TOAST lz4 | 全局默认值 | OLAP 工作负载需手动恢复 JIT |
| 高 | WAIT FOR LSN | 读写分离 | 有 read-your-writes 需求?受益 |
| 中 | 外键插入性能提升 | 高写入规范化 | 有大量 FK 的写入?受益 |
运维治理:并行 Autovacuum 与 REPACK
并行 Autovacuum:大表维护不再是单线程瓶颈
PostgreSQL 18 及之前,autovacuum 对一张表的索引清理是串行的——一个 worker 逐个处理索引。对于有十几个索引的大表,autovacuum 耗时惊人,维护窗口压力巨大。
PostgreSQL 19 允许 autovacuum 使用并行 worker 处理索引清理阶段:
-- 全局设置:允许 autovacuum 使用的最大并行 worker 数ALTERSYSTEMSETautovacuum_max_parallel_workers=3;-- 按表设置:为特定表指定并行 worker 数ALTERTABLEordersSET(autovacuum_parallel_workers=2);同时新增了autovacuum 评分系统,改变了 autovacuum launcher 选择清理哪张表的策略。之前基本是 FIFO(先到阈值先清理),现在会根据死元组数量、freeze 紧急度、multixact 等因素综合评分,优先清理最需要清理的表:
-- 新增系统视图:查看每张表的 autovacuum 评分SELECTrelname,score,autovacuum_countFROMpg_stat_autovacuum_scoresORDERBYscoreDESCLIMIT10;还有一个容易被忽略但很实用的改进:普通查询的表扫描现在也能标记页为 all-visible(之前只有 VACUUM 和 COPY FREEZE 能做)。这意味着高读写表中被频繁扫描的页面,可见性映射更新更及时,Index-Only Scan 能更长时间保持高效。
REPACK:内置的在线表重建
VACUUM FULL能回收膨胀空间,但它持有ACCESS EXCLUSIVE锁——执行期间整张表完全不可读写,对于生产表来说基本等于停服。社区方案一直是第三方扩展pg_repack,效果好但需要额外安装、版本匹配、维护。
PostgreSQL 19 内置了REPACK命令,并支持CONCURRENTLY选项:
-- 在线重建表,不持有长时间排他锁REPACK orders CONCURRENTLY;-- 在线重建并按指定索引聚簇REPACK ordersUSINGINDEXorders_created_at_idx CONCURRENTLY;REPACK ... CONCURRENTLY的工作原理:构建一份紧凑的新副本,同时用变更日志记录重建期间的增量修改,最后在极短的锁窗口内原子切换。读写流量在重建过程中保持正常。
注意事项:CONCURRENTLY用额外 I/O 和磁盘空间换取无锁——它会构建整张表的完整副本。对几百 GB 的大表,先确认磁盘有足够余量,并在生产数据的恢复副本上 benchmark 实际耗时。
监控视图增强
PostgreSQL 19 增强了 vacuum 进度监控:
-- pg_stat_progress_vacuum 新增 started_by 和 mode 列SELECTrelname,phase,started_by,modeFROMpg_stat_progress_vacuum;-- 结果示例-- relname | phase | started_by | mode-- ----------+------------------+------------+-------------- orders | scanning heap | autovacuum | normal-- events | cleaning indexes | user | aggressivestarted_by告诉你这次 vacuum 是 autovacuum 自动触发的还是手动发起的;mode表示激进程度。以前要区分这两者只能翻日志。
性能提升:外键插入与 AIO 自动伸缩
外键检查插入性能约 2 倍提升
任何做过规范化 schema 高频写入的团队都交过"外键税"——每条 INSERT 到带 FK 的表,都要触发引用完整性检查。订单明细引用订单、事件引用实体、日志引用用户,这些表的高频写入都被 FK 检查拖慢。
PostgreSQL 19 优化了外键约束检查路径,在高 FK 负载的批量插入场景下约2 倍性能提升。这个优化不需要你改任何 SQL 或配置,升级即可受益。
验证方法:
-- 在 PG 18 和 PG 19 上分别执行同样的批量插入-- 对比 EXPLAIN ANALYZE 的耗时EXPLAIN(ANALYZE,BUFFERS)INSERTINTOorder_items(order_id,product_id,quantity)SELECTgenerate_series(1,100000),1,1;AIO Worker 自动伸缩
PostgreSQL 18 引入了异步 I/O 子系统。PostgreSQL 19 让它更可运维:io_method = worker模式下,I/O worker 数量会自动伸缩:
-- postgresql.confio_method=worker io_min_workers=1-- 下限:始终保持的 worker 数io_max_workers=8-- 上限:负载高时扩展到不再需要猜一个静态 worker 数量,服务器会根据负载自动扩展和收缩 worker 池。EXPLAIN ANALYZE也增加了 AIO 统计信息,可以看到查询有多少时间花在等待异步读取上。
其他性能改进
- COPY FROM 性能:text 和 CSV 输入使用 SIMD CPU 指令加速。
- NOTIFY 精准唤醒:只唤醒监听指定通道的 backend,不再广播唤醒大部分进程。
- 排序性能:引入 radix sort。
- Hash 索引和 GIN 索引 vacuum:使用 streaming reads 提升 bulk-deletion 性能。
复制与一致性:WAIT FOR LSN 与在线逻辑复制
WAIT FOR LSN:读写分离的"读到刚写的数据"
读写分离的经典痛点:用户在主库写了一条数据,立刻去从库读,但从库还没同步到这条数据,用户看到"数据不见了"。每个团队都绕过这个问题——粘性会话、应用层轮询、延迟容忍——但都不优雅。
PostgreSQL 19 提供了WAIT FOR LSN命令:
-- 应用端流程-- 步骤 1:主库写入,获取当前 LSN-- INSERT INTO orders (...) VALUES (...) RETURNING *;-- SELECT pg_current_wal_lsn(); -- 例如返回 0/16B3748-- 步骤 2:从库等待该 LSN 同步完成WAITFORLSN'0/16B3748';-- 步骤 3:此时查询保证能看到刚写的数据SELECT*FROMordersWHEREid=42;WAIT FOR LSN可以等待到三种同步程度:写入(write)、刷盘(flush)、回放(replay):
-- 等待到 LSN 已回放(最严格)WAITFORLSN'0/16B3748';-- 等待到 LSN 已刷盘WAITFORLSN'0/16B3748'FLUSH;-- 等待到 LSN 已写入(最快,但不保证已回放)WAITFORLSN'0/16B3748'WRITE;在线启用逻辑复制
PostgreSQL 18 及之前,启用逻辑复制需要wal_level = logical并重启服务器——对主库来说是计划内停机。
PostgreSQL 19 允许在wal_level = replica时在线启用逻辑复制,无需重启。新增只读参数effective_wal_level报告实际生效的 WAL 级别:
-- 检查实际生效的 WAL 级别SHOWeffective_wal_level;-- 如果 wal_level = replica 但逻辑复制已激活,这里会显示 logical配合序列同步(sequences 现在可以在订阅者端与发布者保持一致),基于逻辑复制的零停机大版本升级风险显著降低。
逻辑复制其他改进
-- 发布所有表但排除特定表(以前只能逐个列举)CREATEPUBLICATION all_tablesFORALLTABLESEXCEPTTABLEaudit_log,temp_data;-- 基于外部服务器定义订阅(连接信息集中管理)CREATESUBSCRIPTION my_sub SERVER foreign_server_name PUBLICATION my_pub;开发体验:SQL 新特性
这些不影响运维,但日常开发会用到。
ON CONFLICT DO SELECT … RETURNING
-- 以前:想拿到冲突行必须用 DO UPDATE 触发 RETURNINGINSERTINTOusers(email,name)VALUES('a@b.com','Alice')ONCONFLICT(email)DOUPDATESETname=EXCLUDED.nameRETURNING*;-- PG 19:直接用 DO SELECT 拿到冲突行,不做无意义的 UPDATEINSERTINTOusers(email,name)VALUES('a@b.com','Alice')ONCONFLICT(email)DOSELECTRETURNING*;GROUP BY ALL
-- 以前:非聚合列必须逐个列出SELECTdept,role,count(*)FROMemployeesGROUPBYdept,role;-- PG 19:自动按所有非聚合输出列分组SELECTdept,role,count(*)FROMemployeesGROUPBYALL;分区管理:MERGE / SPLIT PARTITION
-- 合并多个分区为一个ALTERTABLEmeasurementsMERGEPARTITIONS(m_2024_01,m_2024_02,m_2024_03)INTOm_2024_q1;-- 就地拆分一个分区为多个ALTERTABLEmeasurements SPLITPARTITIONm_2025INTO(PARTITIONm_2025_h1FORVALUESFROM('2025-01-01')TO('2025-07-01'),PARTITIONm_2025_h2FORVALUESFROM('2025-07-01')TO('2026-01-01'));时间序列和多租户场景以前需要 detach/create/attach 脚本编排的操作,现在一条 DDL 搞定。
SQL/PGQ 属性图查询
PostgreSQL 19 支持用 SQL 标准的图查询语法(SQL/PGQ),直接在关系表上做图查询,不需要引入单独的图数据库:
-- 定义属性图CREATEPROPERTY GRAPH social_network VERTEXTABLES(usersKEY(id))EDGETABLES(friendships SOURCE users DESTINATION usersKEY(id));-- 用图查询语法查找好友的好友SELECT*FROMGRAPH_TABLE(social_networkMATCH(u1ISusersWHEREu1.name='Alice')-[f1ISfriendships]->(u2ISusers)-[f2ISfriendships]->(u3ISusers)COLUMNS(u3.nameASfriend_of_friend));适合多跳关系查询、社交网络分析、知识图谱等场景。
默认值变更与兼容性风险(重点)
这部分是升级前必须排查的——这些默认值变更可能在不经意间影响生产。
1. JIT 默认关闭(影响最大)
-- PostgreSQL 12-18:JIT 默认开启-- PostgreSQL 19:JIT 默认关闭SHOWjit;-- PG 19 返回 offPostgreSQL 团队认为现有的 JIT 成本估算不可靠——对一些本不该用 JIT 的查询错误地触发了编译,导致规划开销增加但收益很小。所以 19 把默认值改成了 off。
影响:
- OLTP 工作负载:几乎不受影响,甚至更快(省去了无效的 JIT 编译开销)。
- OLAP / 分析型工作负载:如果你的大查询之前在静默享受 JIT 加速,升级后可能变慢。
应对:如果你跑分析型工作负载,升级前先在postgresql.conf中显式设置jit = on,benchmark 后再决定。
2. RADIUS 认证移除
# pg_hba.conf 中如果有这行,PG 19 将无法启动 host all all 0.0.0.0/0 radiusPostgreSQL 19 完全移除了 RADIUS 认证支持(因为只支持 UDP,安全性无法修复)。如果你的pg_hba.conf使用了radius,升级后服务器无法启动。迁移到 LDAP、证书或其他认证方式。
3. MD5 密码认证警告
-- PG 18:MD5 标记为 deprecated-- PG 19:MD5 认证成功后会输出警告-- 可通过 md5_password_warnings = off 关闭MD5 密码认证正式走向废弃,每次认证成功都会记录警告。建议迁移到 SCRAM-SHA-256。
4. TOAST 压缩默认改为 lz4
-- PG 18:default_toast_compression = pglz-- PG 19:default_toast_compression = lz4SHOWdefault_toast_compression;-- PG 19 返回 lz4lz4 压缩/解压速度优于 pglz,但已有的 TOAST 数据不会自动重压缩。新写入的数据会用 lz4,存量数据保持 pglz。
5. 其他兼容性变更
| 变更 | 影响 |
|---|---|
max_locks_per_transaction默认值 64 → 128 | 锁表内存翻倍,原来设自定义值的需检查 |
standard_conforming_strings强制为on | 使用\转义的老 SQL 可能行为变化 |
log_lock_waits默认开启 | 日志量增加,注意存储 |
MULE_INTERNAL编码移除 | 使用该编码的库需 dump/restore 转换 |
| inet/cidr 默认索引 opclass 从 btree_gist 改为 GiST | 旧版 btree_gist inet/cidr 索引存在时 pg_upgrade 会失败 |
升级前验证清单
把上面的风险点整理成一份可操作的清单,在升级到 PostgreSQL 19 之前逐项检查。
-- ========== 1. 检查认证方式 ==========-- 检查 pg_hba.conf 中是否有 radius(PG 19 不再支持)-- 命令行:grep radius $PGDATA/pg_hba.conf-- 检查是否有 MD5 认证(会收到警告)-- 检查 pg_hba.conf 中 method 列为 md5 的行-- ========== 2. 检查 JIT 使用情况 ==========-- 如果有分析型大查询,记录当前 jit 设置SHOWjit;SHOWjit_above_cost;SHOWjit_inline_above_cost;SHOWjit_optimize_above_cost;-- 升级后如果发现分析查询变慢,先尝试 jit = on-- ========== 3. 检查编码 ==========-- 确认没有使用 MULE_INTERNALSELECTdatname,pg_encoding_to_char(encoding)ASencodingFROMpg_databaseWHEREpg_encoding_to_char(encoding)='MULE_INTERNAL';-- ========== 4. 检查锁配置 ==========SHOWmax_locks_per_transaction;-- PG 19 默认改为 128,如果你之前自定义了值,需要调整为 2 倍-- ========== 5. 检查 inet/cidr btree_gist 索引 ==========SELECTindexrelid::regclassASindex_name,indrelid::regclassAStable_nameFROMpg_indexWHEREindexrelidIN(SELECToidFROMpg_classWHERErelnameIN(SELECTindexnameFROMpg_indexesWHEREindexdefILIKE'%btree_gist%'));-- 如果存在 btree_gist 的 inet/cidr 索引,pg_upgrade 会失败-- 需要在升级前删除并重建为 GiST 索引-- ========== 6. 检查 TOAST 压缩配置 ==========SHOWdefault_toast_compression;-- PG 19 默认 lz4,确认你的应用是否依赖特定压缩行为-- ========== 7. Benchmark 核心工作负载 ==========-- 在生产数据的恢复副本上:-- a) 对大表跑 autovacuum,对比 18 vs 19 的耗时-- b) 对高 FK 写入表跑批量 INSERT,对比耗时-- c) 对分析型查询跑 EXPLAIN ANALYZE,对比 jit on/off 的差异-- d) 对膨胀表跑 REPACK CONCURRENTLY,验证磁盘空间和耗时-- ========== 8. 检查逻辑复制配置 ==========-- 如果你用逻辑复制做大版本升级:-- a) 测试序列同步是否正确-- b) 测试 CREATE PUBLICATION ... EXCEPT 语法-- c) 验证在线启用逻辑复制(无需重启)总结
PostgreSQL 19 是一个对运维友好的版本,核心价值集中在三个方向:
维护效率:并行 Autovacuum + 评分系统让大表清理不再串行瓶颈;内置 REPACK CONCURRENTLY 替代了 VACUUM FULL 的停机风险和 pg_repack 的外部依赖;普通扫描也能更新可见性映射,让 Index-Only Scan 更持久高效。
性能与一致性:外键插入约 2 倍提升、AIO worker 自动伸缩、WAIT FOR LSN 解决读写分离的 stale read——这些不需要改应用代码,升级即可受益。
默认值变更是最大的升级风险:JIT 关闭影响 OLAP、RADIUS 移除阻断启动、TOAST 换 lz4、锁配置翻倍——这些变化在升级前必须逐一验证,用上面的检查清单在非生产环境跑一遍你的真实工作负载。
现在 Beta 阶段就是测试的最佳时机:用一份生产数据的副本,验证哪些工作负载会受益、哪些兼容性变化需要提前排雷,等 GA 落地时你已经准备好了。
