最近在某客户的生产数据库中发现了一些日志损坏的报错,数据库是瀚高Highgo v9(base on postgresql 14), 这是postgresql中的已知问题,主要原因为index 索引损坏,且在线创建时可能也会出现的错误。
开始是autovacuum 发现的错误信息
ERROR: failed to re-find parent key in index for "%TABLE" deletion target page
CONTEXT: while vacuuming index index_name of relation schema.table
有点像oracle的loss write,表和索引记录无法匹配的问题。(好像是ora-1499), 这种会影响table的vacuum,导致出现膨胀或事务回卷问题。
解决方法
临时可以手动vacuum,使用跳过index的选项, 当然这是临时的,仅对表做vacuum, 并不会解决索引错误的问题。
highgo=# VACUUM (INDEX_CLEANUP OFF ,freeze,verbose) tpk;
INFO: aggressively vacuuming "public.tpk"
INFO: table "tpk": found 0 removable, 1 nonremovable row versions in 1 out of 1 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 810
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM
INDEX_CLEANUP gives you control over whether indexes are cleaned during vacuuming.
解决索引问题,还是要重建索引
REINDEX TABLE CONCURRENTLY your_table_name;
-- or --
REINDEX INDEX your_index_name [CONCURRENTLY];
从 PostgreSQL 12 版本开始,该 CONCURRENTLY选项允许行级锁定,从而显著提高表的可用性。虽然CONCURRENTLY这种方法干扰较小,但在繁忙的数据库中速度可能会较慢。如果可能,请考虑在流量较低的时段构建索引。
当然在reindex时,可能比较忙或大的表,创建失败,因为tid重复,会提示如下报错信息:
ERROR: table tid from new index tuple (1976,14) overlaps with invalid duplicate tuple at offset 46 of block 1746 in index "IDX_xxxx"
用shell 过滤pg log可以定位到所有的索引名称,
解决方法
重试重建索引
REINDEX INDEX your_index_name [CONCURRENTLY];
如果问题重现
vacuum full table_name;
reindex table concurrently table_name;
注意:重建过程中如果有中断情况;记得删除多余的索引!
使用以下查询确认;定位到数据库目前所有的无效索引:
select indexname,indexdef,'drop index'|| indexname||';' from pg_indexes where tablename='table_name';
--使用以下查询也可以定位到数据库目前所有的无效索引:
select indexrelid::regclass,indrelid::regclass::text,* from pg_index where indrelid::regclass::text ='table_name'
and indisvalid is false ;
— over —