什么是MVCC
一种并发控制的方式---------多版本并发控制。其好处主要有两点1.写和读互相不阻塞,因为都是在各自的版本上进行。2.可以回溯之前的版本。MVCC只能解决部分幻读的问题(只读查询)快照读,如果对两个并发的非只读查询的来说,就有可能幻读,原因是执行INSERT、DELETE、UPDATE这些语句时)当前读)是加锁读最新的版本的。为在一个事务运行过程中,只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务id,并且重新生成一个ReadView
。然后我们根据MVCC ReadView
中判断数据行对当前事务是否可见的方式进行判断。具体可以看这个博客的部分。MVCC真的解决幻影读了吗?(事务隔离级别详解) - 掘金
这里主要记录一下不可重复读和幻读的理解。不可重复读可能是针对单个数据来说的,幻读是对数据总量来说的。解决方法------使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。
快速理解脏读、不可重复读、幻读和MVCC - 腾讯云开发者社区-腾讯云
MVCC通用实现
读不加版本,写事务加了版本,还有一个txn status table来维护txn状态。
同时只依赖mvcc做不到serialsizable。如下图,t2要阻塞到RA读完提交才能创建新的version。
版本管理主要有下面三种方式
同时版本不能一直增加,因为比较占空间。所以要gc
同时关系型数据库的index在多版本并发控制下也有一定的挑战
primary index要存储最新versiond的,也就是目前物理地址,同时如果修改pkey的话,是先delete,然后insert的。
但对于secondary index就复杂了。
第一种方法是通过主键来找,回表,但效率不高。第二种,就是 直接存物理地址,但是变化的话,所以的index都要变化
还有重复version的问题
解决方法有两个
就是要支持冗余的key,然后我们拿回来的data里面可能是多版本的,我们要有额外的逻辑来选择。
LevelDB中的MVCC
通过version引用计数,如果变为0的话,就从versionset链表中删除。实际上都是compaction时会记录SSTable变化。
同时SSTable也是引用计数的,如果没有version引用的话,就可以删除了。
VersionEdit记录了每个次变化的文件。VersionEdit
主要有两个作用一个就是应用到版本上作版本变迁,这个就是Builder
做的事情,这主要发生在内存的数据结构中。另外一个作用就是持久化到MANIFEST记录版本变迁的内容(主要两个地方1.初始写入,需要写入当前数据状态的信息2.版本变迁写入,写入的是每一次版本变化的写入)。
当重新打开一个数据库时,需要读取MANIFEST重新构造版本信息,这个版本信息由初始的Version
和多个VersionEdit
生成,如果直接用VersionEdit
应用会生成多个版本,降低了效率。所以使用了Builder
,将多个VersionEdit
的内容累积到Builder
上,然后一次性应用到当前Version
即可生成新的Version
。
同时每个操作都要sequnce number。应该是timestamp 和 mvcc组合起来的。