openGauss系 Wrong Result bug select (*) 与 select * 不同记录
今天在客户一套库发现了个bug, 环境Mogdb 508 onopenEuler
, 在数据库做了主从切换以后,select count(*) 与select *明细记录数不一致, 前者使用index only scan, 后者是index scan , 这种情况在oracle有时也能遇到,通常是索引条目与table条目不一致,如因为lost write导致,可以drop 并create index重建索引恢复,但是opengauss中还是第一次,在postgresql中控制记录的除了table, index还有可见性的vm,简单记录一下该问题。
查询不一致现象
但然我们排除期间表变化,在极短的时间内查询。后来为了返回条目,select 把*改成了索引列。index only scan。
这类问题可以先尝试:
vacuum table 更新VM文件或尝试重建索引。
手动执行vacuum analyze tablexxx 报错;
WARNING: page is not marked all-visible but visibility map bit is set in relation “tabxxxxx” page nnnnn
WARNING: page is not marked all-visible but visibility map bit is set in relation “tabxxxxx” page nnnnn
WARNING: page is not marked all-visible but visibility map bit is set in relation “tabxxxxx” page nnnnn
…
code postgres/src/backend/access/heap/vacuumlazy.c
/* * As of PostgreSQL 9.2, the visibility map bit should never be set if the * page-level bit is clear. However, it's possible that the bit got * cleared after heap_vac_scan_next_block() was called, so we must recheck * with buffer lock before concluding that the VM is corrupt. */ else if (all_visible_according_to_vm && !PageIsAllVisible(page) && visibilitymap_get_status(vacrel->rel, blkno, &vmbuffer) != 0) { elog(WARNING, "page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u", vacrel->relname, blkno); visibilitymap_clear(vacrel->rel, blkno, vmbuffer, VISIBILITYMAP_VALID_BITS); }
原因:
在opengauss社区panweiDB发现也存在该问题的case. 函数调用visiblitymap_clear(), visiblitymap_set(), heap_xlog_allvisiblecleared(),heap_xlog_update().
在回放update时,会从update xlog日志头位置添加两个偏移量,分别是sizeof(TransactionId)和sizeof(CommitSeqNo), 然后读取日志的标志位,根据标志位判断是否修改VM文件,清理数据页可见性标志位。在执行DML操作时会在xlog的末尾追加写入CommitSeqNo(CSN),备节点回放xlog时读取,用于逻辑解码。 但heap_xlog_update接口读取xlog时误认为CSN在xlog的头部,因此添加了该字段的偏移量来获取标志位, 根据标志位判断是否修改VM文件,清理数据页可见性标志位,导致备节点的VM文件错误。
openGauss 3.1.0, mogdb 3.0.6, mogdb 5.0.2 已修复该问题。 目前不确认当前508是否是历史升级前问题。
解决方法:
Index Only Scan查询使用了数据表的VM(visibility map)文件来判断数据元组的可见性,怀疑是vm文件损坏,我们把该表的vm文件移走,然后手动再次vacuum文件。 通过更新vm文件的方法,解决了该问题。
检查路径
select pg_relation_filepath('xx'); cd ... mv *.vm pathto
Note: 如果是主从静止状态,可以hexdump xx.vm 对比主从环境.
目前这篇文章还没有评论(Rss)