Greenplum的MVCC多版本控制的简单介绍(主要涉及cmin,cmax,xmin,xmax说明)

熟悉Greenplum数据库的朋友应该都知道,GP底层是使用PostgreSQL数据库来实行MPP架构的,而对于事务控制这一块,也是使用PostgreSQL的多版本控制MVCC,实现了读写分离,显然就会提高数据库每秒查询的性能。

 

在Read Commit事务隔离级别时,查询请求只读取查询请求之前已经提交的事务的数据更改,对当前版本的数据并不影响;

而DML语句,会操作当前版本。因此做到了读写分离的目的,提高数据库并发能力。

 

我们先来回顾一下PostgreSQL里面的MVCC多版本控制。

在PostgreSQL中,每一个事务都会得到一个被称作为 XID 的事务ID。这里说的事务不仅仅是被 BEGIN - COMMIT 包裹的一组语句,还包括单条的insert、update或者delete语句。当一个事务开始时,PostgreSQL递增XID,然后把它赋给这个事务。PostgreSQL还在系统里的每一行记录上都存储了事务相关的信息,这被用来判断某一行记录对于当前事务是否可见。举个例子,当你插入一行记录时,PostgreSQL会把当前事务的XID存储在这一行中并称之为 xmin。只有那些已提交的而且xmin比当前事务的XID小的记录对当前事务才是可见的。这意味着,你可以开始一个新事务然后插入一行记录,直到你提交( COMMIT )之前,你插入的这行记录对其他事务永远都是不可见的。等到提交以后,其他后创建的新事务就可以看到这行新记录了,因为他们满足了 xmin < XID 条件,而且创建那一行记录的事务也已经完成。

对于 DELETE 和 UPDATE 来说,机制也是类似的,但不同的是对于它们PostgreSQL使用叫做 xmax 的值来判断数据的可见性。这幅图展示了在两个并发的插入/读取数据的事务中,MVCC在事务隔离方面是怎么起作用的。

 

PostgreSQL使用xmin,xmax,cmin,cmax等标记来实现多版本,他们的含义为:

xmin:在创建记录(tuple)时,记录此时的事务id,后面每次update也会更新。

xmax: 在更新或删除tuple或者lock时,记录此时的事务id;如果记录没有被删除,那么此时为0。

cmin:插入该元组的命令在插入事务中的命令标识(从0开始累加)

cmax:删除该元组的命令在插入事务中的命令标识(从0开始累加)

 

但是对于Greenplum数据库来说,它毕竟是基于多个postgres实例来实现MPP架构的数据库,所以上面的标记的值可能与单个postgres有区别。下面我们示例中会说明。

#装载数据,非并行,如果并行加载数据的话,可以考虑使用gpfdist或gpload等方式

zhangyun_db=# COPY test_mvcc from '/home/gpadmin/mvcc.txt' with delimiter as '|' null as '';

COPY 4

zhangyun_db=# select * from test_mvcc ;

 id |   name   

----+-----------

  4 | Hadoop

  3 | Greenplum

  2 | Hive

  1 | Spark

(4 rows)

zhangyun_db=# select t.*, t.xmin, t.xmax, t.cmin, t.cmax from test_mvcc t;

 id |    name    |  xmin  | xmax | cmin | cmax

----+------------+--------+------+------+------

  8 | Flink      | 449908 |    0 |    0 |    0

  4 | Hadoop     | 449906 |    0 |    0 |    0

  5 | HBase      | 449775 |    0 |    0 |    0

  7 | PostgreSQL | 457913 |    0 |    0 |    0

  2 | Hive       | 449910 |    0 |    0 |    0

  3 | Greenplum  | 449909 |    0 |    0 |    0

  6 | HAWQ       | 449899 |    0 |    0 |    0

  1 | Spark      | 449905 |    0 |    0 |    0

(8 rows)

 

从上图可以看出,8条记录的xmin是不一样的(如果是PostgreSQL数据库的话,这里应该是一样的,因为这些数据是通过同一个事务copy创建的)。

另外xmax都为0,说明数据自从导入后就没有被删除。

 

下面我们来演示在Greenplum数据中执行update的情况:

请打开两个linux终端A和B,方便数据比对和查看。

首先在终端A执行,但不提交:

zhangyun_db=# begin;

BEGIN

zhangyun_db=# update test_mvcc set name = 'Hive On Spark' where id = 2;

UPDATE 1

 

终端B查看:

zhangyun_db=# select t.*, t.xmin, t.xmax, t.cmin, t.cmax from test_mvcc t;

 id |    name    |  xmin  |  xmax  | cmin | cmax

----+------------+--------+--------+------+------

  4 | Hadoop     | 449906 |      0 |    0 |    0

  7 | PostgreSQL | 457913 |      0 |    0 |    0

  6 | HAWQ       | 449899 |      0 |    0 |    0

  2 | Hive       | 449910 | 450412 |    0 |    0

  1 | Spark      | 449905 |      0 |    0 |    0

  8 | Flink      | 449908 |      0 |    0 |    0

  5 | HBase      | 449775 |      0 |    0 |    0

  3 | Greenplum  | 449909 |      0 |    0 |    0

(8 rows)

可以看到,对于id为2的数据行的xmax发生了变化,但是数据本身是没有变化的,因为终端A的事务还没有提交。

 

接着,我们在终端A执行提交动作,如下:

zhangyun_db=# commit;

COMMIT

 

同时在终端B再查看:

zhangyun_db=# select t.*, t.xmin, t.xmax, t.cmin, t.cmax from test_mvcc t;

 id |     name      |  xmin  | xmax | cmin | cmax

----+---------------+--------+------+------+------

  2 | Hive On Spark | 450412 |    0 |    0 |    0

  6 | HAWQ          | 449899 |    0 |    0 |    0

  5 | HBase         | 449775 |    0 |    0 |    0

  7 | PostgreSQL    | 457913 |    0 |    0 |    0

  4 | Hadoop        | 449906 |    0 |    0 |    0

  3 | Greenplum     | 449909 |    0 |    0 |    0

  8 | Flink         | 449908 |    0 |    0 |    0

  1 | Spark         | 449905 |    0 |    0 |    0

(8 rows)

可以看到id为2的记录,其xmin已经变化了。

 

根据上面的结果,不知道大家有没有发现,对于Greenplum来说,更新或者删除都没有修改cmin和cmax的值。

在PostgreSQL中,cmin和cmax用于判断同一个事务内的其他命令导致的行版本变更是否可见。如果一个事务内的所有命令严格顺序执行,那么每个命令总能看到之前该事务内的所有变更,不需要使用命令标识。然而一个事务内存在命令交替执行的情况,比如使用游标进行查询。Fetch游标时看到的是声明游标时的数据快照而不是Fetch执行时,即声明游标后对数据的变更对该游标不可见。

这一块的内容,后续抽时间分析源码再写一篇文章进行分析。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值