mvcc 简介

MVCC(Multi-Version Concurrency Control,多版本并发控制)是数据库中用于解决并发访问冲突的核心机制,广泛应用于InnoDB、PostgreSQL等主流数据库。其核心思想是为数据维护多个版本,使得读写操作可以并发执行而不互相阻塞,从而在保证事务隔离性的同时提升并发性能。

为什么需要MVCC?

传统的并发控制依赖锁机制(如行锁、表锁),但锁会导致读写冲突(例如:读操作需要等待写操作释放锁,或写操作等待读操作释放锁),在高并发场景下严重影响性能。

MVCC通过让读操作访问数据的历史版本,避免了对当前写入版本的依赖,从而实现"读不加锁、写不阻塞读",极大提升了并发效率。

MVCC的核心原理

MVCC的实现依赖三个关键组件:隐藏列undo日志Read View(读视图)

1. 隐藏列:数据版本的"身份标识"

数据库表中的每行数据,除了用户定义的列外,还会隐含几个系统列(以InnoDB为例):

  • DB_TRX_ID:记录最后一次修改该数据行的事务ID(6字节)。
  • DB_ROLL_PTR:回滚指针(7字节),指向该数据行的上一个版本(存储在undo日志中)。
  • DB_ROW_ID:行唯一标识(6字节),当表没有主键时,InnoDB会用它生成聚簇索引。

这些隐藏列是MVCC追踪数据版本的基础。

2. undo日志:数据版本的"历史档案"

当事务修改数据时,数据库会先将数据的旧版本写入undo日志(回滚日志),然后再更新当前数据行。

  • 例如:事务T1修改了一行数据,旧版本会被存入undo日志,当前数据行的DB_ROLL_PTR指向这个旧版本;若事务T2再次修改该行,新的旧版本(T1修改后的版本)会被存入undo日志,DB_ROLL_PTR更新为指向T2的旧版本,形成一条版本链(通过回滚指针串联的历史版本)。
  • undo日志的另一个作用是事务回滚:若事务执行失败,可通过undo日志恢复数据到修改前的状态。
3. Read View:判断版本可见性的"规则"

Read View(读视图)是事务在读取数据时生成的一个"快照",用于判断当前事务能看到哪个版本的数据。它包含四个核心参数:

  • m_ids:当前活跃事务的ID集合(即尚未提交的事务)。
  • min_trx_id:m_ids中最小的事务ID(当前活跃事务的最小ID)。
  • max_trx_id:数据库下一个将要分配的事务ID(大于当前所有活跃事务ID)。
  • creator_trx_id:生成该Read View的事务自身的ID。
4. 可见性判断规则

当事务读取数据时,会通过Read View判断数据版本链中哪个版本对自己可见,规则如下(假设数据版本的DB_TRX_IDtrx_id):

  1. trx_id == creator_trx_id:该版本是当前事务自己修改的,可见。
  2. trx_id < min_trx_id:修改该版本的事务已提交(因为其ID小于所有活跃事务ID),可见。
  3. trx_id >= max_trx_id:修改该版本的事务是在当前事务之后启动的,不可见。
  4. min_trx_id <= trx_id < max_trx_id
    • trx_idm_ids中(该事务仍活跃):不可见。
    • trx_id不在m_ids中(该事务已提交):可见。

如果当前版本不可见,事务会通过DB_ROLL_PTR回溯到上一个版本,重复判断,直到找到可见版本或版本链结束(此时返回空)。

MVCC与事务隔离级别的关系

MVCC的行为会根据事务隔离级别调整,核心差异在于Read View的生成时机

  • Read Committed(读已提交):每次执行查询时都会生成新的Read View。因此,同一事务中两次查询可能看到不同的结果(因为中间可能有其他事务提交)。
  • Repeatable Read(可重复读,InnoDB默认):仅在事务第一次执行查询时生成Read View,后续查询复用该视图。因此,同一事务中多次查询看到的结果一致(避免了不可重复读)。

(注:Serializable隔离级别通常不依赖MVCC,而是通过加锁实现;Read Uncommitted直接读取最新版本,不适用MVCC。)

MVCC的优势

  1. 读写不冲突:读操作无需加锁,直接访问历史版本;写操作仅锁定当前版本,不阻塞读,极大提升并发性能。
  2. 简化隔离级别实现:通过Read View的生成时机和可见性规则,自然实现了Read Committed和Repeatable Read隔离级别的语义。
  3. 避免锁竞争:减少了传统锁机制的阻塞和等待,降低了死锁风险。

总结

MVCC通过隐藏列记录版本标识undo日志维护历史版本链Read View判断可见性,实现了"多版本并发访问"。其核心价值是在保证事务隔离性的前提下,最大化读写并发效率,是现代数据库高性能的关键机制之一。

相关推荐
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德3 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫3 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i3 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.3 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
jiunian_cn3 小时前
【Redis】渐进式遍历
数据库·redis·缓存
橙露4 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot
冰暮流星4 小时前
sql语言之分组语句group by
java·数据库·sql
符哥20084 小时前
Ubuntu 常用指令集大全(附实操实例)
数据库·ubuntu·postgresql