关于 PolarDB PostgreSQL 版
PolarDB PostgreSQL 版是一款阿里云自主研发的云原生关系型数据库产品,100% 兼容 PostgreSQL,高度兼容Oracle语法;采用基于 Shared-Storage 的存储计算分离架构,具有极致弹性、毫秒级延迟、HTAP 、Ganos全空间数据处理能力和高可靠、高可用、弹性扩展等企业级数据库特性。同时,PolarDB PostgreSQL 版具有大规模并行计算能力,可以应对 OLTP 与 OLAP 混合负载。
PolarDB PostgreSQL版中"xmin"
PolarDB PostgreSQL中存在各类xmin,有用于可见性、vacuum、prune page、page recyclable等等地方的判断。
extern PGDLLIMPORT TransactionId TransactionXmin;
extern PGDLLIMPORT TransactionId RecentXmin;
extern PGDLLIMPORT TransactionId RecentGlobalXmin;
extern PGDLLIMPORT TransactionId RecentGlobalDataXmin;复制
"xmin"计算
TransactionXmin:
获取快照时获取当前的快照能看到的最小值;计算方式从polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid
中获取,polar_oldest_active_xid
中维护当前的最老的活跃事务,事务提交或abort时都可能会修改polar_oldest_active_xid
,从而保证维护一个最老的活跃事务;
RecentXmin:
获取快照时获取当前的快照能看到的最小值;计算方式从polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid
中获取。与TransactionXmin
不同的是,RecentXmin
获取快照时都会重新计算当前的最老的活跃事务。
RecentGlobalDataXmin:
typedef struct PGXACT
{
TransactionId xid; /* id of top-level transaction currently being
* executed by this proc, if running and XID
* is assigned; else InvalidTransactionId */
TransactionId xmin; /* minimal running XID as it was when we were
* starting our xact, excluding LAZY VACUUM:
* vacuum must not remove tuples deleted by
* xid >= xmin ! */
/*
* POLAR csn
* When transaction committing, record commit csn in PGXACT with CommitSeqNoLock hold.
* For now, only used in GetRunningTransactionData to iterate ProcArray and filter out
* committed xacts in active xacts list.
* If committed, value is csn, else InvalidTransactionId.
*/
CommitSeqNo polar_csn;
/* ... */
} PGXACT;复制
PGXACT
中会记录自身的事务xid,以及它获取快照时能看到的最小xid
记录在xmin
。所以遍历所有的procarry
对应的pgxact
中xid
和xmin
、以及所有的replication slot的xmin
中的最小值作为RecentGlobalXmin
;
RecentGlobalXmin
RecentGlobalXmin
在RecentGlobalDataXmin
基础上还考虑了replication slot catalog xmin;
所以它们之间的大小关系 **RecentGlobalXmin <= RecentGlobalDataXmin <= TransactionXmin**
;
使用
RecentGlobalXmin
与GetOldestXmin()
使用区别:绝大部分场景使用的是RecentGlobalXmin/RecentGlobalDataXmin
,因为GetOldestXmin
计算主要会遍历ProcArray
,会加ProcArrayLock
锁,所以如果每个需要oldestXmin位置都重新计算可能会带来性能影响。由于RecentGlobalXmin
是一个相对较老的值,但是获取一个相对较老的值来做判断并不会给正确性带来影响。所以,RecentGlobalXmin/RecentGlobalDataXmin
的使用地方替换成GetOldestXmin()
是不会有任何正确性问题,但是会带来性能问题。
GetOldestXmin()主要用在几处:
vacuum时会计算 oldestXmin = GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM)
。同时利用oldestXmin - freezemin
差值作为本次vacuum的 FreeLimit。oldestXmin
主要用于判断tuple是否满足vacuum的条件(利用HeapTupleSatisfiesVacuum
函数判断,实现如下图)。

update datfrozenxid时会计算 newFrozenXid = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM)
;
其他场景基本都用RecentGlobalXmin/RecentGlobalDataXmin
。