首页 » PostgreSQL/GaussDB » openGauss系 Wrong Result bug select (*) 与 select * 不同记录

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)

我要评论