| 作者 | 时间 | QQ技术交流群 |
|---|---|---|
| perrynzhou@gmail.com | 2023/03/20 | 672152841 |

Snapshot
介绍
发起一个事务,这个事务最终只能看到一个版本的行数据,但是
PG
中一个数据页中的一行记录会包含一个或者多个版本数据。所有不同row
的可见版本构成Snapshot
.Snapshot
仅包含创建快照时时提交的数据,从而为这一特定时刻提供了一致的数据视图。

每个事务都有自己的快照,这就意味着不同的事务看到不同的在不同时间点的快照数据。在
RR
隔离级别,快照创建是在第一个事务语句的开始一直到整个事务的完成;而对于RC
隔离级别快照创建是在事务的每个语句的执行时,并且事务中语句执行期间保持活跃状态
Tuple
的可见性
PG中的快照并不是物理意义上的数据拷贝而是通过在
Tuple Header
中定义一些字段,其Row
可见性是由特定的规则决定。PG中每一行数据都包含Tuple Header
,Tuple header
定义了xmin(数据插入的事务好)
、xmax(删除行数据时候的事务ID)
、相关的提示位。快照中的每行数据仅仅由一个版本的行数据表示。行课件的规则相对比较复杂,我们这里可以简单的说明下。快照中一行数据可见的规则是事务开始之前
Tuple Header
中的xmin
可变动但是xmax
必须不能变动且事务commited
,这表明可见的tuple
没有被删除。在事务内部,本事务是可以看到未提交的数据变更,如果事务aborted
,这行数据变更在任何快照中都不可见

事务2是在快照创建之前提交,因此事务2对于行数变更可见;事务1的活跃时间持续到了快照创建,因此事务1对于行数变更不可见;事务3开始在快照创建之后,因此事务3对于行数据变更不可见
Snapshot
结构

snapshot
在PG源码中的结构是由struct SnapshotData
表示,快照被创建时候这个结构中部分字段被初始化。新开启的xid
(事务ID)小于SnapshotData->xmin
(下边界)行数据可见;事务ID大于等于SnapshotData->xmax
行数据不可见在实际中事务的ID在
SnapshotData->xmin<= XID <=SnapshotData->xmax
且该事务不在SnapshotData->xip
中,该事务是可以看到快照中的行数据的。
typedef struct SnapshotData
{
// 快照类型
SnapshotType snapshot_type; /* type of snapshot */
// 事务ID小于min,tuple都可见
TransactionId xmin;
// 事务ID大于xmax,tuple不可见
TransactionId xmax;
// 当前所有的活跃事务的ID列表
TransactionId *xip;
// 活跃事务的个数
uint32 xcnt;
// 活跃的子事务列表
TransactionId *subxip;
// 走事务的个数
int32 subxcnt; /* # of xact ids in subxip[] */
bool suboverflowed; /* has the subxip array overflowed? */
bool takenDuringRecovery; /* recovery-shaped snapshot? */
bool copied; /* false if it's a static snapshot */
CommandId curcid; /* in my xact, CID < curcid are visible */
/*
* An extra return value for HeapTupleSatisfiesDirty, not used in MVCC
* snapshots.
*/
uint32 speculativeToken;
/*
* For SNAPSHOT_NON_VACUUMABLE (and hopefully more in the future) this is
* used to determine whether row could be vacuumed.
*/
struct GlobalVisState *vistest;
/*
* Book-keeping information, used by the snapshot manager
*/
uint32 active_count; /* refcount on ActiveSnapshot stack */
uint32 regd_count; /* refcount on RegisteredSnapshots */
pairingheap_node ph_node; /* link in the RegisteredSnapshots heap */
TimestampTz whenTaken; /* timestamp when snapshot was taken */
XLogRecPtr lsn; /* position in the WAL stream when taken */
/*
* The transaction completion count at the time GetSnapshotData() built
* this snapshot. Allows to avoid re-computing static snapshots when no
* transactions completed since the last GetSnapshotData().
*/
uint64 snapXactCompletionCount;
} SnapshotData;
在PG内部实现中,包含了多种不同类型的快照类型,具体含义参照如下





