游乐游手机版
首页/数据库/文章详情

PGv19预发布对生产系统的隐患分析

时间:2026-06-10 07:04
PostgreSQL19Beta1发布,新特性包括:JIT默认关闭、checksums在线启停、组合事务号扩展至64位终结回卷风险、autovacuum并行化并引入优先级评分、升级迁移支持扩展统计信息恢复、安全链路支持多域名证书、逻辑复制补齐序列、优化器重新支持被短路的布尔分支。这些变化对现有生产系统既带来启发也存在隐患。

PostgreSQL 19 Beta 1 昨晚正式发布了。最近仔细啃了一遍 release notes,这里把几个值得关注的新特性拎出来聊聊——它们对现有生产系统是启发多还是隐患多,值得提前掂量一下。

  • 参数 JIT 默认关闭
  • checksums 在线启停
  • 组合事务号回卷被终结
  • autovacuum 并行且分主次
  • 升级迁移的最后一公里 + 最后 100 米
  • 安全链路连接支持多域名证书
  • 逻辑复制补齐序列
  • 优化器重新支持被短路的分支

一、参数 JIT 默认保持关闭

v19 有两个参数值发生了显著变化:

jit = off
default_toast_compression = lz4

其实 v14 就开始推荐使用 lz4 压缩 toas 字段了,v19 正式把默认值从 pglz 切到了 lz4,不过编译时得带上 --with-lz4 选项。

JIT(即时编译)从 v11 引入时可是个重磅特性,它借助 LLVM 提升 WHERE 条件、目标列表、聚合以及内部操作的表达式执行速度。要启用它,先得装好 LLVM,然后源码编译时加上 --with-llvm。从 v12 到 v18,jit 参数默认都是 on。

但社区收集了大量用户反馈后发现,在偏 OLTP 的场景下 JIT 很难带来明显收益,所以 v19 索性把它默认关掉了,OLAP 场景需要手工开启。release notes 里原话是这样描述的:

二、checksums 在线启停

以前需要开启 checksums 来校验数据文件块的完整性时,生产环境只能 offline 操作——先停库,再启用:

  • offline
$ pg_ctl stop -D PGDATA
$ pg_checksums --enable -D PGDATA

要不要默认开启 checksums,或者 initdb 时强制开启,社区已经争论了好几个大版本。v19 借助 CPU 硬件加速实现了 checksums 的高效处理:

并提供了 SQL 接口函数,支持在线平稳启停:

  • online
SQL function:pg_enable_data_checksums()
SQL function:pg_disable_data_checksums()

同时 data_checksums 的观测值变成了 onoffinprogress-oninprogress-off。调用这两个函数期间,会有短暂的窗口能观察到中间状态。

三、组合事务号回卷被终结

事务号回卷对数据库来说就像灾难降临。当前的 autovacuum 会根据系统资源情况进行预警或自救:

  • 当事务号资源剩余 1 亿时,数据库日志会发出预警(v19 之前是 4000 万)
  • 当事务号资源剩余 300 万时,触发安全边界,数据库只读不写,自救启动
ERROR: database is not accepting commands ..

这是从事务号资源的角度看。而从表上死元组的清理年龄角度,反映的是同一件事:

从表格的两列参数对比可以清晰看到,组合事务与普通事务是两条独立的线脉,处理机制类似。

但组合事务回卷的问题在 v19 算是被终结了。社区收到了真实用户反馈和验证,32 位组合事务确实很容易消耗殆尽引发故障。v19 把它加宽到了 64 位,并新增了 pg_get_multixact_stats() 函数来监控组合事务的统计信息:

select * from pg_get_multixact_stats();
-[ RECORD 1 ]----+-----
num_mxids        | 207
num_members      | 452
members_size     | 2260
oldest_multixact | 1

当然,普通事务依然是 32 位,社区认为大多数常规场合没那么容易消耗完 21 亿资源。

四、autovacuum 并行且分主次

手工 VACUUM 从 v13 开始就已经支持并行能力:

19=# VACUUM (VERBOSE, PARALLEL 3) t;
INFO:  vacuuming "evantest.public.t"
INFO:  launched 2 parallel vacuum workers for index vacuuming (planned: 2)
...
parallel workers: index vacuum: 2 planned, 2 launched in total
...
memory usage: dead item storage 2.00 MB accumulated across 1 reset (limit 64.00 MB each)
...

v19 把同一套并行机制应用到了 autovacuum 上:针对单表的索引清理阶段可以并行化。前期的 Heap Scan 和后期的 Heap Truncation 两个流程仍然未并行化。举个例子,一张表有 N 个索引,可以将这些索引分配给 N 个 Worker 同时清理。控制参数是 autovacuum_max_parallel_workers 以及表级参数 autovacuum_parallel_workers

生产环境里另一个 autovacuum 的难题是:某个核心表膨胀了,却因为等待队列排队迟迟清理不了。以往的 autovacuum 收集需要处理的表清单是先进先出、后进后出原则。v19 引入了 score 机制来解决排队问题:根据 insert、analyze、xmin、frozenxid 等因子打分,按重要性来处理:

select * from pg_stat_autovacuum_scores where relname='tab';
-[ RECORD 1 ]-------+---------------------
relid               | 16472
schemaname          | public
relname             | tab
score               | 0.01996008044823684
xid_score           | 0.00028279
mxid_score          | 5.175e-07
vacuum_score        | 0
vacuum_insert_score | 0.000999800027789852
analyze_score       | 0.01996008044823684
do_vacuum           | f
do_analyze          | f
for_wraparound      | f

五、升级迁移的最后一公里 + 最后 100 米

以前用 pg_upgrade 进行大版本升级后,还得手工更新统计信息,例如:

vacuumdb --all --analyze-in-stages

v18 增加了两个系统函数来恢复表对象和表字段的基本统计信息:

SELECT * FROM pg_catalog.pg_restore_relation_stats(
        'version', '180000'::integer,
        'schemaname', 'public',
        'relname', 'tab1',
        'relpages', '345'::integer,
        'reltuples', '10000'::real,
        'relallvisible', '345'::integer,
        'relallfrozen', '0'::integer
);
SELECT * FROM pg_catalog.pg_restore_attribute_stats(
        'version', '180000'::integer,
        'schemaname', 'public',
        'relname', 'tab1',
        'attname', 'col',
        'inherited', 'f'::boolean,
        'null_frac', '0'::real,
        'a vg_width', '4'::integer,
        'n_distinct', '100'::real,
        'most_common_vals', '{1,..}'::text,
        'most_common_freqs', '{0.01,..}'::real[],
        'correlation', '0.009082272'::real
);

pg_dump 工具使用 --statistics-only 封装调用接口,这样 pg_upgrade 可以自动恢复基本统计信息。但用户如果创建了扩展统计信息(例如 CREATE STATISTICS test_stats (ndistinct, dependencies, mcv) ON id, descr FROM test;),升级后仍然需要手工处理。

v19 紧接着打通了最后 100 米——增加了 pg_restore_extended_stats() 系统函数来恢复扩展统计信息:

SELECT * FROM pg_catalog.pg_restore_extended_stats(
'version', '190000'::integer,
'schemaname', 'public',
'relname', 'test',
'statistics_schemaname', 'public',
'statistics_name', 'test_stats',
'inherited', 'f'::boolean,
'n_distinct', '[{"attributes": [1, 2], "ndistinct": 1}]'::pg_ndistinct,
'dependencies', '[{"attributes": [1], "dependency": 2, "degree": 1.000000}, {"attributes": [2], "dependency": 1, "degree": 1.000000}]'::pg_dependencies,
'most_common_vals', '{{1,a}}'::text[],
'most_common_freqs', '{1}'::doubleprecision[],
'most_common_base_freqs', '{1}'::doubleprecision[]
);

六、安全链路连接支持多域名证书

v19 给服务端加上了 SNI(Server Name Indication)支持。没有 SNI 之前,使用 SSL 时一个数据库实例只能绑定一个域名一套证书,不同 hostname 无法使用不同的 TLS 证书。其实 v14 已经在客户端层面支持发送 SNI,但那是铺垫性工作,服务端会忽略它。v19 终于把服务端的能力补齐了,支持多域名证书:

服务端的实现机制:

  • 通过 GUC 参数 ssl_sni 进行开关控制
dconfig+x ssl_sni
List of configuration parameters
-[ RECORD 1 ]-----+--------
Parameter         | ssl_sni
Value             | off
Type              | bool
Context           | sighup
Access privileges |
  • 通过 pg_hosts.conf 配置文件进行映射

当客户端发起 TLS 请求,服务端接收并回调,提取 hostname,然后查询 pg_hosts.conf,再切换到不同的证书和密钥文件。

七、逻辑复制补齐序列

逻辑复制从 v10 发布以来,每个大版本都在持续迭代功能和提升稳定性。2024 年曾有一篇文章详细介绍过逻辑复制从 v10 到 v16 的七大工艺,但限制依然不少:不支持 DDL、仅支持大事务并行应用、不支持并行解码、不支持单表粒度开启逻辑复制等等。

v19 终于补齐了长久以来缺失的序列支持:

此外 v19 还对逻辑复制做了多项改进,包括:

  • 动态调整 WAL LEVEL:需要使用逻辑复制时 WAL LEVEL 自动增强为 logical,不使用时自动降级为 replica

  • 为 REPACK (CONCURRENTLY) 提供技术支撑

  • 发布端支持黑名单列表EXCEPT 通常搭配 FOR ALL TABLES 使用)

CREATE PUBLICATION p1
  FOR ALL TABLESEXCEPT TABLE public.audit_log, public.session_cache;
  • 订阅端连接串可使用 FDW server 统一管理

八、优化器重新支持被短路的分支

这个特性比较隐蔽。release notes 里的描述是:

打开提交链接,标题是:

这个提交标题的描述和 release notes 里的描述有点不一样,尤其是 "Re-allow" 这个词——重新允许、重新支持。翻译过来就是:优化器重新支持被短路的布尔值分支。

这事要从 v12 讲起。v12 给函数增加了一个 support 特性,能让优化器更准确地预估行数。因为函数对优化器来说像黑盒,基本不可见,典型场景是 Function Scan 预估的行数不准:

没有 support 属性时,函数只能依赖 pg_proc 中固定的 procostprorows。v12 引入 support 属性的同时,也短路了某条老路径——也就是 boolvarsel 分支。

下面这张图(GPT 辅助生成)清晰地展示了短路逻辑:

简单说,v12 引入 support function 的同时也埋下了一个隐藏 bug。6 年后的今天,社区终于修复了它。所以提交标题很诚实:WHERE 条件中的 bool-valued 函数被短路、不能使用统计信息的这个分支场景,如今可以重新使用了。

这个 bug 分支非常隐蔽,用户很难主动发现。触发条件需要满足:使用了 bool-valued function、存在表达式或扩展统计信息、同时函数没有 support 属性。

注:boolvarsel 是数据库内部函数,用于布尔表达式选择率估算。

PS:release notes 里的重头笔都在描绘优化器,其中也不乏一些 bug fix 的特性,还有一个貌似也像:

来源:https://juejin.cn/post/7648686322055790655
上一篇RAG向量数据库选型:OpenSearch、Weaviate、pgvector对比 下一篇MySQL中外键知识全面详解与实战应用总结
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
金仓数据库逻辑备份实战:全库导出与模式替换全流程
数据库 · 2026-07-03

金仓数据库逻辑备份实战:全库导出与模式替换全流程

在长期的运维实践中,我越来越体会到,备份就像一份保险——平时看似无用,但关键时刻却是唯一的救命稻草。逻辑备份看似简单,可真正执行恢复时,各种陷阱接连浮现:表名大小写不一致、Schema 未正确切换、Owner 属性未同步修改……任何一个环节处理不当,最终恢复出的数据库就会与预期相去甚远。 本文将深入

金仓数据库sys_rman物理备份全流程演练与误覆盖恢复
数据库 · 2026-07-03

金仓数据库sys_rman物理备份全流程演练与误覆盖恢复

干运维这行,逻辑备份和物理备份我都接触过,但说句实在话,真正能在生产环境里扛住事儿的,还得是物理备份。逻辑备份导出的是 SQL 语句,数据量一大,那速度慢得让人抓狂,而且最关键的是,它没法做时间点恢复。物理备份不一样,它直接拷贝数据文件,再配上 WAL 归档日志,想恢复到过去哪一秒都行,这是它最硬核

Windows下将MySQL注册为系统自启服务教程
数据库 · 2026-07-03

Windows下将MySQL注册为系统自启服务教程

先说一个关键前提:务必以管理员身份运行终端,否则 mysqld --install 这条命令几乎不可能成功。问题不在于命令写错,而是 Windows 系统的用户账户控制(UAC)机制会在中途拦截——在普通 CMD 或 PowerShell 窗口执行这条命令,要么直接提示 Access is deni

Mac版Navicat中快速对比两个数据库的表结构异同
数据库 · 2026-07-03

Mac版Navicat中快速对比两个数据库的表结构异同

直接说结论:Mac 版 Navicat 和 Windows 版在表结构比对逻辑上完全一致。但默认配置下,它确实无法承受“全库一键比对上万张表”的压力。要想避免卡死、内存溢出、进度条永远停在 0%,你必须手动将表分批处理,或者利用前缀过滤来控制扫描范围。 为什么 Mac 上点击「结构同步」后界面会卡住

MySQL中UNION操作推荐用UNION ALL的原因
数据库 · 2026-07-03

MySQL中UNION操作推荐用UNION ALL的原因

MySQL中UNION与UNION ALL性能对比:别再被“保险”迷惑,差距远超预期 先给出核心结论:UNION ALL 的性能通常比 UNION 高出不止一个数量级。原因在于,UNION 在合并结果集后会自动触发去重操作,这往往伴随着隐式排序,进而产生临时表和文件排序。而 UNION ALL 则直