Postgres pg_upgrade corrupt indexes (UK) 缺失值,但基于索引的选择缺失记录

Postgres pg_upgrade corrupt indexes (UK) missing values though missing records by index based selects

在 9.6->12.3 pg_upgrade 之后我们标记了一些严重的 select 给出了缺失的结果! REINDEX 或 drop / create 解决了这个问题。

升级要点

  1. 停止 9.6
  2. rsync 9.6数据和bin文件Centos7 Centos8(预装12)
  3. pg_upgrade
  4. ./analyze_new_cluster.sh
  5. ./delete_old_cluster.sh

我们在每个数据库中发现 1-3 个唯一的损坏索引。每个索引错过大约 20 个值。

我们发现了一个非常有用的工具amcheck! https://www.postgresql.org/docs/10/amcheck.html

SELECT bt_index_check(c.oid), c.relname, c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree' AND n.nspname = 'pg_catalog'
-- Don't check temp tables, which may be from another session:
AND c.relpersistence != 't'
-- Function may throw an error when this is omitted:
AND i.indisready AND i.indisvalid
ORDER BY c.relpages DESC LIMIT 10;

非常重要:注释掉(AND n.nspname = 'pg_catalog' + LIMIT 10)验证限制,运行 bt_index_check 也对您的索引起作用!

是的,如果找到损坏的索引,函数会抛出异常。

为什么索引会出错? 我们如何确保我们的新数据库是一致的并且升级成功?

Why does index go wrong?

最可能的解释是 CentOS 7 和 CentOS 8 之间的 glibc 版本不同。

This blog post 对此提供了更多见解。

一般来说,在更改 glibc 版本时(例如,由于系统补丁或 OS 升级),您应该 re-index 所有包含 textvarcharchar 列。

这不是 Postgres 可以直接影响的东西,尽管使用 ICU 归类的能力是该问题的部分答案。但是如果操作系统的 ICU 版本更新了(例如,由于系统补丁再次隐式更新)你会在那里遇到同样的问题(但似乎 ICU 库的更新频率低于 glibc 库)

我认为正在进行一些工作以至少警告用户。但据我所知,当前版本 12 或即将发布的版本 13 中没有任何内容。