一、MVCC(Multiversion Concurrency Control多版本并发控制)
PostgreSQL的并发控制机制在维护一致性和完整性的同时,尽量避免读写堵塞。
传统数据库使用锁机制来避免事务看到不一致的数据,但这会导致请求进入等候队列,甚至超时未处理。基于锁的机制被称为悲观机制,因为它是预防性的:读阻塞写,写阻塞读,导致并发性能较差。
MVCC(多版本并发控制)被称为乐观机制,因为它是后验性的:读不阻塞写,写不阻塞读,提交时才检测冲突。没有锁的情况下,读写不会相互阻塞,从而提升并发性能。
MVCC通过避开传统的锁机制,最大限度减少锁竞争,以提高多用户环境中的性能。适当使用MVCC通常比锁机制提供更好的性能。对于无法适应MVCC的应用,PostgreSQL也提供了表和行级的锁机制。
1、PG多版本并发控制
MVCC(Multiversion Concurrency Control多版本并发控制)
原理图如下:
2、PG多版本并发控制的实现
MVCC多版本标记关键词
XID — 数据库的事务ID
xmin,xmax, 行头部的XID信息
xmin表示插入或更新这条记录的事务XID
xmax表示删除这条记录的事务XID
xid_snapshot : 当前集群中的未结束事务
clog : 事务提交状态日志
数据修改过程如下:
- backend 开启一个事务,获得事务号 XID;
- 在事务中对数据的任意修改都被 XID 标记;
- 其他 backend 扫描数据时,根据隔离级别决定是否可见这些被 XID 修改的数据(默认的读已提交隔离级别看不到这些数据);
- 只有当 XID 被标记为 commit(写 WAL commit log 和 clog)后,其他 backend 才能看到这个 XID 修改的数据。
数据可见性条件:
- 记录的头部XID早于当前事务(repeatable read要求,read committed不要求);
- 记录的头部XID不在当前的XID快照中(即事务状态不是未提交);
- 记录头部的XID在CLOG中显示为已提交。
PG中事务快照的文本形式
xmin:xmax:xip_list
100:104:100,102
xmin 最早仍然活跃的事务的txid
xmax 第一个尚未分配的txid(例如只开启一个begin)
xip_list 获取快照时活跃事务的txid列表
3、MVCC多版本标记字段
每个表的每行数据(称为tuple)包含4个隐藏字段,可直接访问:
- xmin:记录插入tuple时的事务ID。
- xmax:默认值为0,删除tuple时记录此值。
- cmin和cmax:标识同一事务中多个语句命令的序列值,从0开始,用于版本可见性判断。
4、MVCC优势和劣势
1、优势
读操作不会阻塞写,写操作也不会阻塞读,提高了并发访问的性能
事务的回滚可立即完成,无论事务进行了多少操作
数据可以进行大量更新,不像MySQL和Innodb引擎和Oracle那样需要保证回滚段不会被耗尽
2、劣势
事务ID个数有限制,当事务ID用完时,会出现wraparound问题。
大量过期数据占用磁盘降低查询性能
但是,PG可以通过vacuum应对以上两个问题