MySQL多版本控制-MVCC

1.什么是多版本并发控制(MVCC)

多版本并发控制(MVCC,Multiversion Concurrency Control)是一种数据库并发控制方法,它通过保留数据的多个版本来管理事务并发。与传统的锁机制不同,MVCC 允许多个事务同时读取和写入数据,而不会相互干扰,从而提高数据库的并发性和性能。

 

2 MVCC如何实现

2.1每行数据包含隐藏字段:

必选隐藏字段‌(始终存在):

DB_TRX_ID‌:记录最后一次修改该行数据的事务 ID‌

DB_ROLL_PTR‌:指向 Undo Log 的指针,用于回溯历史版本数据‌

条件性隐藏字段‌:

DB_ROW_ID‌:当表未显式定义主键且无唯一索引时,InnoDB 自动生成的隐藏主键‌;若存在自定义主键或唯一索引,则不会生成此字段‌

 

如上图所示,针对id=10001的这条数据,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被 roll_pointer 属性连接成一个链表,我们把这个链表称之为版本链,根据版本链就可以找到这条数据历史的版本。

2.2 Undo Log(回滚日志)

如2.1图所示,针对id=10001的这条数据,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,用于回滚和一致性读‌,随着更新次数的增多,所有的版本都会被 roll_pointer 属性连接成一个链表,我们把这个链表称之为版本链,根据版本链就可以找到这条数据历史的版本

利用undo log日志我们已经保留下了数据的各个版本,那么现在关键的问题是要读取哪个版本的数据呢? 这时就需要用到ReadView了,通过 Read View 判断数据版本的可见性

‌2.3 Read View(读视图)‌

ReadView就是事务在使用MVCC机制进行快照读操作时产生的一致性视图

事务启动时生成,包含以下信息:

●m_ids: 指的是在创建 ReadView 时,当前数据库中「活跃事务」的事务 id 列表,注意是一个列表, “活跃事务”指的就是,启动了但还没提交的事务。
min_trx_id: 指的是在创建 ReadView 时,当前数据库中「活跃事务」中事务 id 最小的事务,也就是 m_ids 的最小值。
max_trx_id:这个并不是 m_ids 的最大值,而是创建 ReadView 时当前数据库中应该给下一个事务的 id 值,也就是全局事务中最大的事务 id 值 + 1;
creator_trx_id :指的是创建该 ReadView 的事务的事务 id, 只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为 事务分配事务id,否则在一个只读事务中的事务id值都默认为0。

 

通过 Read View 判断数据版本的可见性,

√ DB_TRX_ID = creator_trx_id  表示当前事务在访问它自己修改过的记录,可见

√ DB_TRX_ID < min_trx_id 表示该版本在事务开始前已提交,可见

× DB_TRX_ID > = max_trx_id 表示这个版本是由将来启动的事务生成的,不可见的

× DB_TRX_ID 属于 m_ids 表示这个版本是由还没提交的事务生成的,不可见, 

√ DB_TRX_ID 不属于 m_ids 表示创建Read View时生成该版本的事务已经提交,可见 

这种通过版本链 + 一致性视图 来控制并发事务访问同一个记录时的行为就叫 MVCC(多版本并发控制)。

3. MVCC 与隔离级别的关系

READ COMMITTED隔离级别下 : 每次 SELECT 生成新 Read View,总读取已提交的最新快照‌

REPEATABLE READ隔离级别下 : 事务首次 SELECT 生成 Read View,后续读操作复用该视图,保证可重复读‌

4.优点:

实现读写操作的非阻塞(读操作无需等待写操作释放锁)‌

避免传统锁机制带来的死锁风险和高并发下的性能瓶颈‌

5.缺点:

历史版本数据需存储于 Undo Log,增加存储开销‌

频繁更新场景下,版本链过长可能影响查询效率‌

6‌.优化建议‌

‌控制事务长度‌:避免长事务导致 Undo Log 堆积和版本链过长‌

‌合理选择隔离级别‌:优先使用 REPEATABLE READ 平衡一致性与性能‌

‌定期清理历史版本‌:通过配置 innodb_purge_threads 清理无效 Undo Log‌

 
 
posted @ 2025-03-17 20:59  侯蜀黍  阅读(85)  评论(0)    收藏  举报