本地建设网站软件下载,wordpress整站密码,青海省建筑信息平台,搭建购物商城文章目录 0.简介1.MVCC介绍2.MVCC常见的实现方式3.PG的MVCC实现3.1 可见性判断3.2 提交/取消 0.简介
本文主要介绍在事务模块中MVCC(多版本并发控制#xff09;常见的实现方式#xff0c;优缺点以及PG事务模块中MVCC#xff08;多版本并发控制#xff09;的实现。
1.MVCC… 文章目录 0.简介1.MVCC介绍2.MVCC常见的实现方式3.PG的MVCC实现3.1 可见性判断3.2 提交/取消 0.简介
本文主要介绍在事务模块中MVCC(多版本并发控制常见的实现方式优缺点以及PG事务模块中MVCC多版本并发控制的实现。
1.MVCC介绍
MVCCMulti-Version Concurrency Control多版本并发控制是一种用于数据库管理系统中的并发控制的方法。在传统的并发控制中常用的简单方式是通过加锁来保证某一时刻数据只被一个事务修改但这种方式可能会带来并发度的下降尤其在高并发场景下很可能导致性能瓶颈。MVCC主要通过维护数据的多个版本来解决传统锁机制的一些局限性每个事务可以看到一个特定版本从而使得读写操作可以互不干扰地执行其核心在于对于每个修改不直接在原始数据上修改而是创建一个新的数据版本来做修改其他事务依然可以访问旧的数据以此来提高并发度。当然MVCC也有其局限性比如在高并发场景下可能因为多个版本导致占用较高内存。
2.MVCC常见的实现方式
MVCC常见的实现方式有两种 1修改旧数据前备份在写新的数据时把旧的数据备份到单独的一块空间其他事务读取数据时可以在备份空间中获取比如MySQL innodb引擎的回滚段。 2新数据不直接修改而是采用插入的方式。 以上两种方式功能上都能实现MVCC都需要占用一定的空间两者相比较二的事务回滚更为方便不会出现备份空间用尽的问题一的话清理上会更为简单不会导致数据扫描使得读数据增加。PG采用的是二即采用插入方式实现的MVCC。
3.PG的MVCC实现
3.1 可见性判断
MVCC的实现首先要有版本的概念下面来看PG中的定义然后以一个实际的例子来分析可见性的判断定义如下
typedef struct HeapTupleFields
{TransactionId t_xmin; /* inserting xact ID */TransactionId t_xmax; /* deleting or locking xact ID */union{CommandId t_cid; /* inserting or deleting command ID, or both */TransactionId t_xvac; /* old-style VACUUM FULL xact ID */} t_field3;
} HeapTupleFields;struct HeapTupleHeaderData
{union{HeapTupleFields t_heap;DatumTupleFields t_datum;} t_choice;ItemPointerData t_ctid; /* current TID of this or newer tuple (or a* speculative insertion token) */....
}可以看到在上面代码结构中每个元组头部存储事务的t_xmin(数据插入的事务idt_xmax(数据删除或更新的事务id如果为0则表示还未被删除和更新这两个值一旦被设计就不会再次变化。 下面通过一个例子来看一个更新操作的修改以及可见性的判断。 上述描述了向当前表插入了一条数据的过程初始a2,b2的记录是由事务id为10的事务插入xmax为0即还没被删除或更新然后执行update语句将a的值设置为6xmax的值更新为11表示由id为11的事务删除同时新增一条记录不在原记录修改此时虽然有两条数据但其实应该只有一条所以需要根据事务的快照和提交的记录来进行判断也就是可见性的判断。 在PG中是用snapshot来获取那些事务正在执行通过snapshot来区分事务是正在执行还是已经完成了如果事务尚未完成那么事务的更新和写入对其他事务来说是不可见的。snapshot数据结构如下
typedef struct SnapshotData
{SnapshotSatisfiesFunc satisfies; /* tuple test function */TransactionId xmin; /* all XID xmin are visible to me */TransactionId xmax; /* all XID xmax are invisible to me */TransactionId *xip;uint32 xcnt; /* # of xact ids in xip[] */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 its a static snapshot */CommandId curcid; /* in my xact, CID curcid are visible */uint32 speculativeToken;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 */
} SnapshotData;其中所有XIDxmin已完成的的事务都可见所有XIDxmax的事务都不可见而介于xmin和xmax之间的事务可能已完成也可能进行中所以需要一个数组来存储xip如果在xmin和xmax之间的事务id在这个数组被发现说明事务正在进行且尚未完成不可见。 获取数据时会先根据snapshot来判断事务是否已完成如果未完成则不可见对于已完成的需要判断时提交还是取消查询clog来进行判断。这里还有个性能优化就是使用tuple中标志位来进行判断减少clog查询。
3.2 提交/取消
在PG中一个事务最终状态可能有两种Commit/Abort。 1Commit提交时会写WAL和CLOG提交后对于其他事务可见。 2Abort: abort时会写WAL和CLOGabort后对于其他事务不可见。