资讯 PostgreSQL 18.6 的两个坑:GIN 索引的 reltuples 可能变成 Infinity,逻辑解码输出插件默认被收紧

2026-09-30 21:05:43

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 自带的两个插件:

  • pgoutput
  • test_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 比较的整数溢出。

来源:PostgreSQL 18.6 Release Notes

复制全文 生成海报 PostgreSQL 数据库 升级

推荐文章

程序员茄子在线接单