PG-多版本并发控制

多版本并发控制(Multi-Version Concurrency Control,MVCC),是数据库中并发访问数据时保证数据一致性的一种方法

1. 原理

1)  在并发操作中,当正在写时,如果有用户在读,这时写可能只写了一半,如一行的前半部分刚写入,后半部分还没有写入,这时可能读的用户读取到的数据行的前半部分数据是新的,后半部分数据是原来的,这就导致了数据一致性问题。解决这个问题的最简单的方法是使用读写锁,写的时候不允许读,正在读的时候也不允写,但这种方法会导致读和写的操作不能并发执行。于是,有人想到了一种能够让读写并发执行的方法,这种方法就是MVCC。MVCC方法是写数据时,原数据并不删除,并发的读还能读到原数据,这样就不会有数据一致性问题了。

2)  实现MVCC的方法有以下两种。
·第一种:写新数据时,把原数据移到一个单独的位置,如回滚段中,其他用户读数据时,从回滚段中把原数据读出来。
·第二种:写新数据时,原数据不删除,而是把新数据插入进来。PostgreSQL数据库使用的是第二种方法,而Oracle数据库和MySQL数据库中的InnoDB引擎使用的是第一种方法。


3)  如上所述,每张表上都有4个系统字段“xmin”“xmax”“cmin”“cmax”,这4个字段就是为多版本的功能而添加的。当两个事务同时访问记录时,通过参考xmin和xmax的标记判断记录的版本,根据版本号与自己当前的事务标识进行比较,确定自己的数据权限。当删除数据时,记录并没有从数据块中被删除,空间也没有立即释放。
***PostgreSQL的多版本实现中首先要解决的是原数据的空间释放问题。PostgreSQL通过运行Vaccum进程来回收之前的存储空间,默认PostgreSQL数据库中的AutoVacuum是打开的,也就是说,当一个表的更新量达到一定值时,AutoVacuum自动回收空间。当然也可以关闭AutoVacuum进程,然后在业务低峰期手动运行VACUUM命令来回收空间。在PostgreSQL中,若一个事务执行失败,在数据文件中该事务产生的数据并不会在事务回滚时被清理掉。为什么要这样做呢?为什么不在
事务提交时把这些数据标记成有效,而在事务回滚时把这些数据标记成无效呢?这是出于效率的考虑。若事务提交或回滚时再次标记数据,那这些数据就有可能会被刷新到磁盘中,再次标记会导致另一次I/O,从而降低性能。那么如何知道这些数据是有效还是无效呢?PostgreSQL通过记录事务的状态来实现。数据行上记录了xmin和xmax,只需了解xmin和xmax对应的事务是成功提交还是回滚了,就可以知道这些数据行是否有效。PostgreSQL把事务状态记录在Commit Log中,简称
CLOG,CLOG在数据目录的pg_clog子目录下
osdba@osdba-VirtualBox:~/pgdata$ ls -l pg_clog
total 8
-rw------- 1 osdba osdba 8192 Nov 30 21:43 0000

2. 事务的4种状态

1)
·TRANSACTION_STATUS_IN_PROGRESS=0x00:表示事务正在进行中。
·TRANSACTION_STATUS_COMMITTED=0x01:表示事务已提交。
·TRANSACTION_STATUS_ABORTED=0x02:表示事务已回滚。
·TRANSACTION_STATUS_SUB_COMMITTED=0x03:表示子事务已提交。

2)事务ID,在PostgreSQL中有时缩写为xid,是一个32bit的数字。有以下3个特殊的事务ID是给系统内部使用的,代表特殊的含义。
·InvalidTransactionId=0:表示是无效的事务ID。
·BootstrapTransactionId=1:表示系统表初使化时的事务ID。
·FrozenTransactionId=2:冻结的事务ID。

3)所以数据库系统第一个正常的事务ID是从3开始的,然后连续递增,达到最大值后,再从3开始。事务ID为0、1、2的始终保留。通常,使用值为0的事务ID是为了让内部编程更为方便,当PostgreSQL内部的事务ID设置为0时,表示它是一个无效的事务ID。比如,使用函数GetCurrentTransactionIdIfAny查询当前的事务ID时,如果返回的事务ID为0,则表示当前还没有分配事务ID。值为1的事务ID是Initdb服务初始化系统表时在表上填写的事务ID,此时数据库还没有启动,但在系统表中的cmin下也需要一个有效的事务ID,这个事务ID就为1,示例如下:
os dba=# select cmin, cmax, relname from pg_class where relname in ('pg_type','pg_attribute');
cmin | cmax | relname
------+------+--------------
1 | 1 | pg_type
1 | 1 | pg_attribute
(2 rows)

3. PostgreSQL多版本的优劣分析

Oracle数据库和MySQL数据库的InnoDB引擎也都实现了多版本的功能,但它们与PostgreSQL的实现方式是不一样的,在这两个数据库中,旧版本的数据并不记录在原先的数据块中,而是被记录在回滚段中,如果要读取旧版本的数据,需要根据回滚段的数据重构旧版本数据。

--相对于InnoDB和Oracle,PostgreSQL的多版本的优势在于以下几点:
1)·事务回滚可以立即完成,无论事务进行了多少操作。
2)·数据可以进行很多更新,不必像Oracle和InnoDB那样需要经常保证回滚段不会被用完,也不会像Oracle数据库那样,经常遇到“ORA1555”错误的困扰。

--相对于InnoDB和Oracle,PostgreSQL的多版本的劣势在于以下几点:
1)·旧版本数据需要清理。PostgreSQL清理旧版本称为VACUUM,并提供了VACUUM命令进行清理。
2)·旧版本的数据会导致查询更慢一些,因为旧版本的数据存储于数据文件中,查询时需要扫描更多的数据块
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韶博雅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值