PostgreSQL 18.6 的两个坑:GIN 索引的 reltuples 可能变成 Infinity,逻辑解码输出插件默认被收紧
PostgreSQL 18.6 于 2026-08-13 发布,包含自 18.4 起的一批修复。Release Notes 见 PostgreSQL 18.6 Release Notes。
其中前两条不只是代码修复,还涉及升级后的配置调整与数据校准,DBA 需要主动处理。
一、并行 GIN 建索引会写坏 reltuples,且不会自愈
(修复者 Jan Nidzwetzki, Tomas Vondra)
并行构建 GIN 索引时,worker 可能上报未初始化的「已处理行数」,结果写进 pg_class.reltuples 的就是虚假值,极端情况下会变成 Infinity 或 NaN。
后果不是查询结果错,而是统计信息与自动维护彻底失灵:autovacuum 与 autoanalyze 依据 reltuples 判断表是否需要处理,一旦这个值虚高或者为 Infinity/NaN,它们会永远认为该表不需要处理。关键点在于这种状态不会自愈——自动机制自己不会去纠正它。
检查哪些表中招
先看带 GIN 索引的表,reltuples 是否明显大于实际行数:
SELECT c.oid::regclass AS tbl,
c.reltuples,
pg_size_pretty(pg_table_size(c.oid)) AS size
FROM pg_class c
WHERE c.relkind IN ('r', 'm')
AND EXISTS (
SELECT 1
FROM pg_index i
JOIN pg_class ic ON ic.oid = i.indexrelid
JOIN pg_am am ON am.oid = ic.relam
WHERE i.indrelid = c.oid
AND am.amname = 'gin'
)
ORDER BY c.reltuples DESC;
再直接筛出 Infinity / NaN 这一类绝对异常值:
SELECT c.oid::regclass AS tbl, c.reltuples
FROM pg_class c
WHERE c.reltuples <> c.reltuples -- NaN
OR c.reltuples = 'Infinity'::real
OR c.reltuples = '-Infinity'::real;
修复方式
两条路,任选其一:
对相关表手动执行
ANALYZE:ANALYZE your_table;或者在该表上再建一个索引,把
reltuples重置为正确值。
修复后再跑一遍上面的查询确认。如果库里 GIN 索引较多(JSONB、数组、全文检索字段),建议在升级到 18.6 后统一筛查一轮。
二、新增 output_plugin_libraries,逻辑解码插件默认被收紧
(Jacob Champion)
18.6 引入服务器参数 output_plugin_libraries,把逻辑解码可用的输出插件限制在该参数指定的集合内。默认值只包含 PostgreSQL 自带的两个插件:
pgoutputtest_decoding
也就是说,如果部署里用了第三方输出插件(各种 CDC / 同步工具的实现),升级之后这些插件默认不再被允许加载。必须把它们手动加进 output_plugin_libraries,逻辑复制槽才能继续工作。
升级到 17+ 时 pg_upgrade --check 会失败
从 17 及更高版本迁移时存在一个前置阻塞点:如果新集群的 output_plugin_libraries 不允许旧集群逻辑复制槽所用的插件,pg_upgrade --check 会直接失败。
处理顺序是:在 pg_upgrade 之前,先在新集群的配置里把这个参数补上。可以在旧集群上确认槽用到哪些插件:
SELECT slot_name, plugin, database FROM pg_replication_slots;
把结果里出现的插件名全部加进新集群的 output_plugin_libraries,再做 pg_upgrade --check。
三、pgcrypto 能识别不支持的 cipher,并新增绕过选项
(Daniel Gustafsson)
contrib/pgcrypto 的 PGP 加密现在会检测不支持的 cipher。默认行为是报错。为了仍然能取回数据,新增选项 ignore-cipher-failure=1,可加到:
pgp_pub_decrypt()pgp_sym_decrypt()
作用是允许剥掉有问题的加密外层,把内层数据取出来。
四、其余值得留意的条目
- psql:脚本化的
COPY ... FROM STDIN即使在发送PGRES_COPY_IN之前就失败,现在也会跳过脚本中随后的行内数据(Tom Lane)。 - REINDEX CONCURRENTLY 与延迟唯一性约束。
- REJECT 从 SQL 调用接收或返回
internal类型的函数。 - 检查数据类型的 USAGE 权限。
- 角色变更后使依赖角色的缓存计划失效。
- 在 direct SSL connection 之后拒绝
GSSEncRequest。 - contrib/amcheck 限制
search_path。 - 移除 contrib/refint 的计划缓存。
- 逻辑复制元组列数做运行时校验。
- btree_gist 的 float4/float8 NaN 处理。
- ltree 比较的整数溢出。