• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

postgreSQL——并发控制5多版本并发控制

武飞扬头像
YOUTH11111111
帮助1

2021@SDUSC

目录

概述

MVCC相关数据结构

MVCC与快照

 总结


概述

PostgreSQL为开发者提供了丰富的管理数据并发访问的工具。在内部,PostgreSQL利用多版本并发控制( MVCC, Multi- Version Concurrency Control)来维护数据的一致性。这就意味着当检索数据时,每个事务看到的只是一段时间之前的数据快照,而不是数据的当前状态。这样,如果对每个数据库会话进行事务隔离,就可以避免一个事务看到其他并发事务的更新而导致不一致的数据。
使用多版本并发控制的主要优点是对检索(读取)数据的锁请求与写数据的锁请求并不冲突,所以读不会阻塞写,而写也从不阻塞读。这就极大地提高了并发处理能力。
 

多版本并发示例
事务T1 事务T2 表A的变化 事务T2的查询结果
BEGIN SELECT*FROM A; A A
UPDATE   A->AA  
  SELECT * FROM A;   A
COMMIT      
  SELECT * FROM A;   AA

MVCC相关数据结构

在PostgreSQL系统中,更新数据时并不是用新值覆盖旧值,而是在表中另开辟一片空间来存放
新的元组,让新值与旧值同时存放在数据库中,通过设置一些参数,让系统识别它们。
PostgreSQL的数据以元组的形式存放在表中,同时存储该元组相关的描述信息,这些信息存储
在HeapTupleFields中。
 

  1.  
     
  2.  
    typedef struct HeapTupleFields
  3.  
    {
  4.  
    TransactionId t_ xmin;//创建此tuple的XID .
  5.  
    TransactionId t_ xmax;//删除此Tuple的XID
  6.  
    union {
  7.  
    ComnandId t_cid;//创建或者删除Tuple的command ID(即Cmin和Cmax),也可能两者都保存
  8.  
    TransactionId t_ xvac;//清理操作的事务ID
  9.  
    }t_ field3 ;
  10.  
    }HeapTupleFields;

从HeapTupleFields结构中可以看出,Xmin、Cmin、Xmax、Cmax和Xvac这五个字段被保存在三个物理空间中,Xmin 和Xmax分别有独立的字段存储,而Cmin、Cmax 和Xvac共享一个字段。因为Cmin和Cmax都只在创建或删除事务的运行期间内有效,而一般情况下,在同一个事务中创建并
删除同一个元组的概率比较低,Cmin 和Cmax同时存在有效值的概率也就很小,所以把它们放在同一个物理空间中。如果一个事务确实创建并删除了同一个元组,则我们使用一个ComboCommandID来保存Cmin和Cmax。Combo Command ID保存的是一个到实际Cmin和Cmax的映射。另一方面,Xvac字段只由VACUUM FULL命令设置,此时并不需要Cmin和Cmax。
在PostgreSQL中,Combo Command ID是32位的,所以可以映射到2个{ Cmin, Cmax} 组合。在最坏的情况下,每个命令把它之前所有命令创建的元组都删除掉,假设这些命令总共有N个,那
么,系统需要的Combo Command ID有N*(N 1)/2个。在这种最坏的情况下,Combo Command ID最多可以保存92682个命令。在实际应用中,用户在达到这个命令限制之前,就已经耗尽了内存和硬盘空间,所以,把ComboCommandID设置成32位是足够的。.
除了存储元组的事务、命令控制信息外,还需要存储元组的相关控制信息。这些信息存储在元
组的头部HeapTupleHeaderData中。
 

  1.  
    typedef struct HeapTupleHeaderData
  2.  
    {
  3.  
    union
  4.  
    {HeapTupleFields t_ heap;
  5.  
    DatumTupleFields t_ datum;
  6.  
    }t_ choice ;
  7.  
    ItemPointerData t_ ctid;//本元组或者新新元组的当前TID
  8.  
    uint16 t_ infomask2;//标志位(属性、标志位的数量)
  9.  
    uint16 t_ infomask;//标志位(元组的事务信息)
  10.  
    uint8 t_ hoff;//头部长度
  11.  
    bits8 t_ bits[1];//填充位,起标记作用
  12.  
    } HeapTupleHeaderData;

一个新元组被保存在磁盘中的时候,其t_.ctid就被初始化为它自己的实际存储位置。如果这个元组被更新了,该元组的L ctid 字段就指向更新后的新元组。由此可以看出,一个元组是最新版本的,当且仅当它的xmax空或者它的t ctid 指向它自己。如果要找到某个元组的最新版本,只需遍历由t _ctid构成的链表即可。
在HeapTupleHeaderData中,还有一个重要的字段(1_ infomask) 用来表示当前元组的事务信息
 

  1.  
    tdefine HEAP_ HASNULL 0x0001
  2.  
    tdefine HEAP_ HASVARWI DTH 0x0002
  3.  
    #define HEAP_ HASEXTERNAL 0x0004
  4.  
    idefine HEAP_ HASOID 0x0008
  5.  
    户以上四种标志不涉及元组可见性判断,用于表示元组本省的基本信息*/
  6.  
    idefine HEAP_ COMBOCID 0x0020 //复合命令
  7.  
    #define HEAP. XMAX_ EXCL LOCK 0x0040 // xmax 持有排他锁
  8.  
    tdefine HEAP_ XMAX_ SHARED LOCK 0x0080 /* xmax持有共享锁*/
  9.  
    *如果LOCK位被设置了,表示Xmax只是锁住了该元组,没有完成删除*/
  10.  
    tdefine HEAP_ IS_ LOCKED (HEAP_ _XMAX_ EXCL_ LOCK | \
  11.  
    HEAP_ XMAX_ SHARED LOCK)
  12.  
    #define HEAP_ XMIN_ COMMITTED 0x0100 //t_ xmin已提交
  13.  
    tdefine HEAP_ XMIN_ INVALID 0x0200 //t_ xmin 无效/中断
  14.  
    #define HEAP_ XMAX_ COMMITTED 0x0400 /* t_ xmax已提交*/
  15.  
    #define HEAP_ XMAX_ INVALID 0x0800 /* t_ xmax无效/中断*/
  16.  
    #define HEAP_ XMAX_ IS_ MULTI 0x1000 /*组合事务*/
  17.  
    tdefine HEAP_ UPDATED 0x2000 /*更断后的新元组*/
学新通

MVCC的基本原理如图所示,有两个并发执行的事务T1、T2, T1将元组C更新为C',但T1没有提交,此时假如事务T2要对该元组进行查询,它会通过C和C'中的头信息中的Xmin和Xmax及tjinfomask 来判断出C为其有效版本,而C'为无效版本。
学新通

MVCC与快照

快照( SnapShot)记录了数据库当前某个时刻的活跃事务列表。通过快照,可以确定某个元组
的版本对于当前快照是否可见。

  1.  
    typedef struct SnapshotData
  2.  
    {
  3.  
    SnapshotSatisfiesFunc satisfies;//函数指针
  4.  
    TransactionId xmin;//所有XID< xmin对当前快照可见
  5.  
    TransactionId xmax; //所有XID>= xmax对当前快照可见
  6.  
    uint32 xcnt;//当前活跃事务的长度
  7.  
    TransactionId * xip;、/当前活跃事务的链表
  8.  
    int32 subxcnt;//当前活跃子事务个数
  9.  
    TransactionId *subxip;//当前活跃子事务的链表
  10.  
    CommandId curcid;//当前命令的序号
  11.  
    uint32 active_ count;//在活跃快照链表里的引用计数
  12.  
    uint32 regd_ count;//在已注册的快照链表里的引用计数
  13.  
    bool copied;//是否为共享内存中的全局快照
  14.  
    } SnapshotData;

SnapshotData的结构对于事务的可见性判断提供了统一操作接口,其中satisfies 函数指针指向
前面介绍的MVCC相关判断函数,通过该接口可以判断指定的事务ID对于当前快照是否可见。
在PostgreSQL系统中,默认有7种形式的快照,分别是:
SnapshotData SnapshotNowData - {HeapTupleSatisfiesNow};
SnapshotData SnapshotSel fData = {HeapTupleSatisfiesSelfl;
SnapshotData SnapshotAnyData = { HeapTupleSatisfiesAny}; 
SnepshotDato snopshotToastDato - {HeapTupleSatisfiesToast};
SnapshotData Cur rentSnapshotData = (HeapTupleSat isfiesMVCC);
SnapshotData SecondarySnapshotData={HeapTupleSatisfiesMVCC};
#define InitDi rtySnapshot (snapshotdata) \
( (snapshotdata). satisfies = HeapTupleSatisfiesDirty)
其中,不同的快照用于不同形式的可见性判断,需要注意的是如果当前事务的隔离级别是可串行化,那么只存在CurrentSnapshotData, 不存在SecondarySnapshotData, 而在读已提交的隔离级别,这两种快照都存在。

 总结

本周分析了postgreSQL中多版本并发控制机制,下周要分析一下日志处理相关内容,欢迎批评指正。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgjjkcf
系列文章
更多 icon
同类精品
更多 icon
继续加载