众所周知,Greenplum内部支持MVCC多版本并发控制,通过MVCC技术,可以支持同一行数据的读写并发问题,从而大大提升并发访问控制的能力。
GP中的MVCC实现
所谓多版本,其含义在于数据的更新和删除操作并不是直接在原数据上直接进行修改,而是通过把原数据标记为失效的数据,再在新版本中增加新数据的方式,数据具有多个版本。
在Greenplum中,每条数据上有两个标识信息,一个是数据的创建信息XMin,一个是数据的删除信息XMax。XMin是数据插入时的事务ID,XMax则是数据删除时的事务ID。
在Greenplum中有一个用来保存所有事务ID状态的文件pg_xact,其中存储了所有事务ID的状态信息,如committed、aborted、in progress。在查询的时候,结合每条记录中的XMin、XMax以及pg_xact中的事务状态信息,来判断数据的可见性。
以下图为例,当一条数据被插入时,值为40的xmin被生成出来,它代表插入数据所在的事务ID为40。
在处理删除时,并不会直接把数据抹掉,而是记录另一个信息xmax,xmax的值47代表数据被删除所在的事务ID。
对于更新操作,它包含两个部分,一个是删除老的数据,一个是增加新的数据。对于删除老数据,逻辑与前面的删除数据的逻辑一致,也是记录xmax信息。增加新数据的记录中xmin值与删除老数据的xmax值相同。
因此Greenplum的MVCC的特点如下:
- 每个数据都带有版本信息。xmin代表数据写入的版本,max代表数据删除的版本。如果数据经过多次的更新,历史的版本也会保留下来。
- 数据的更新或删除不影响原来数据在磁盘或文件中的位置 。数据更新后,原来的行会被标记为删除,行的位置所在的空间还在,新记录不会替换老数据,老数据的指针非常有效。
数据可见性判断
基于上述MVCC技术实现,可以非常简单的实现数据的可见性判断。
以下图为例,红色和绿色的线都代表了某一个具体的事务范围。假设当时的快照点为100,在这个时间点上,事务B和E已经已经完成,因此是可见的。事务F在100以后发生,因此显然是不可见的。最主要的是对于事务A、C和D,这几个事务虽然事务已经开始,也在数据中生成了对应的事务ID,但是在100的时候可能还未结束。那么我们就需要有一个地方可以保存事务的当前状态,也就是上面我们提到的pg_xact。在快照ID为100的时刻,我们只能看到处于提交或回滚的事务。
在此补充一点,如果数据在事务中是删除操作,但最终事务被abort或回滚,那么数据还是可见的,对应记录中可以查看到xmin和xmax的信息。之所以能查看到对应的记录,是因为pg_xact文件中记录了xmax值对应的事务状态为aborted。
关于事务状态的记录
上面我们说所有事务的状态都保存在pg_xact文件中,pg_xact是保存了所有事务ID及对应状态的文件。
状态主要包括三种:
- committed
- aborted
- in progress
每种状态在文件中以二进制的形式表达。下图示例中表示某个记录正在处于被删除的事务中未提交。
注意,事务文件随着时间会越来越大,因此在Greenplum中需要定期通过vacuum机制进行垃圾回收。