mvcc 的全称是(Multi-Version Concurrency Control)多版本并发控制。此机制是为了解决事务之间同时读写造成的锁导致阻塞。
在数据库中多个用户对一张表的操作,可以简单的概括为三种状态。
- 一张表,多个用户同时读取数据。(读读)
- 一张表,一个用户读数据,一个用户写数据。(读写)
- 一张表,多个用户同时写数据。(写写)
像是第一种情况不会出现冲突,多个用户可以同时执行。第三种情况是肯定有冲突不能同时执行。而第二种情况之前有一种很简单粗暴的解决办法,就是加锁但是这样的效率很低,而 mvcc 机制则是将表中每次更改的记录都保存下来,如果有多个用户进行读写操作,那么读数据的用户所看到的只会是历史数据。执行写操作的用户只要事务没有提交,在事务中所执行的变更对于其他用户来说都是不可见的。
事务与隔离
- 事务
什么是事务?简单的说,事务就是将多个操作捆绑成一个操作。所有的操作要么同时执行成功,要么同时执行失败全部回滚成初始状态不会有第三种可能。这就是事务中非常重要的一个概念 “原子性”。
一致性:一个事务的执行不能破坏数据库的完整性和一致性,比如如果从 A 账户转账到 B 账户,不可能因为 A 账户扣了钱,而 B 账户没有加钱。
隔离性:是指多个事务并发执行时,应该是互相隔离,不可相互干扰。此性质下文会详细解释。
持久性:是指事务一旦提交数据就必须永久保存,就算遇到系统或者服务器的故障也不会丢失。
隔离的四个级别
一:读未提交 Read uncommitted 可能出现脏读,不可重复读,幻读。
一个事务读到另外一个事务还没有提交的数据。
二:读已提交 Read committed 可能出现不可重复读,幻读。
一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。
三:读可重复 Repeatable read 可能出现幻读。
一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了 “幻影”。
四:序列化 Serializable
在该级别下,事务是按照串行化的顺序执行,可以避免脏读,重复读,幻读。虽然可以避免以上的几种问题但是此级别的效率可想而知是非常低的。
在 greenplum 中每一行数据,有 4 个隐藏字段。虽然这四个字段是隐藏的,但可以访问。
xmin :在创建(insert)记录(tuple)时,记录此值为插入 tuple 的事务 ID。
xmax :默认值为 0. 在删除 tuple 时,记录此值。
cmin 和 cmax :标识在同一个事务中多个语句命令的序列值,从 0 开始,用于同一个事务中实现版本可见性判断。
mvcc 机制的相关实验
- 建表
- 开启一个事务,插入记录,查看当前的事务号,可以看到隐藏的四个字段值,只有 xmin 变成了 13511。
- 开两个窗口,一个窗口更新数据,一个窗口更新数据前查一次,更新后查一次。可以看到 xmax 已经改变,因为 pg 更新数据是先删除后插入所以 xmax 会发生变更。
这样就证明了,greenplum 中,读写时不冲突的。