MySQL 的 MVCC机制

7
15·MySQL 的 MVCC(多版本并发控制,Multi-Version Concurrency Control)机制是为了在多个事务并发访问时,确保数据一致性,同时尽可能提升数据库的并发性和性能。它主要通过为数据的每个操作保留多个版本,从而避免加锁的竞争,实现高效的并发处理。下面将详细说明 MVCC 的工作原理、事务隔离级别下的表现、回滚日志机制,以及它的优缺点。
1.MVCC 的核心原理
MVCC 的核心是通过数据版本化(versioning)来实现事务的并发控制。每次更新数据时,MySQL 不直接覆盖旧的数据,而是生成一个新版本的记录,这样每个事务可以看到一个与其隔离级别相符合的数据快照。
1.1隐藏列
在 InnoDB 存储引擎中,每一行数据都有两个隐藏列:
trx_id: 记录最后一次修改该行的事务的 ID。roll_pointer: 指向 Undo Log(回滚日志)的指针。通过该指针,可以找到该行数据的历史版本。
1.2Undo Log(回滚日志)
每当事务修改某行数据时,InnoDB 会将该行数据的旧版本存储在 Undo Log 中。Undo Log 通过roll_pointer 与数据记录相连。当其他事务需要读取数据时,可以通过trx_id 确定它应该看到哪个版本的数据。如果数据已经被修改,那么通过roll_pointer 可以找到该行的旧版本数据。
回滚日志不仅用于 MVCC 读取历史数据,还用于事务回滚操作。当事务回滚时,MySQL 可以利用 Undo Log 将数据恢复到修改前的状态。
1.3版本控制与事务隔离
每个事务都有一个唯一的事务 ID(trx_id),由系统递增分配。事务开始时,它会记录此时数据库中所有已提交数据的快照。在查询时,事务通过与trx_id 的比较来确定应该看到的数据版本:
- 对于已经提交的事务,事务可以看到它们的最新数据版本。
- 对于未提交的事务,它只能看到这些事务开始时的快照数据(即历史版本),避免了读取未提交的数据。
2.MVCC 与事务隔离级别
MySQL 提供四种事务隔离级别,它们通过 MVCC 的不同实现来提供一致性和性能之间的权衡。
2.1读未提交(Read Uncommitted)
- 在读未提交级别,事务可以读取其他事务未提交的数据。这意味着事务可能会读到脏数据(Dirty Read),即读到其他事务已经修改但尚未提交的内容。
- 在这种隔离级别下,MVCC 机制不会生效,读取操作直接读取当前最新的数据版本,可能产生并发问题。
2.2读已提交(Read Committed)
- 读已提交级别允许事务只能读取已提交的数据,每次查询都会看到最新的已提交数据版本。这意味着事务不会读到其他事务未提交的数据,避免了脏读。
- 但不同的查询可能会看到不一致的数据快照,导致不可重复读(Non-repeatable Read)。因为每次查询都可能看到其他事务在此期间提交的新数据版本。
在这个隔离级别,事务在每次执行SELECT 时,都会重新生成一个快照,因此不同查询看到的数据可能不同。
2.3可重复读(Repeatable Read)
- 可重复读级别确保在同一个事务中,事务的每次查询看到的数据快照是一致的,即使其他事务在期间提交了数据更新,当前事务也不会看到变化的数据。这避免了不可重复读。
- 该隔离级别通过 MVCC 实现了快照一致性,事务开始时创建一个数据快照,直到事务结束,读操作总是基于这个快照。
此外,InnoDB 的可重复读级别还避免了幻读(Phantom Read)问题,通过 Gap 锁(间隙锁)来避免新插入的数据对查询产生影响。
2.4串行化(Serializable)
- 在串行化级别,事务之间通过加锁机制完全串行化执行。这是最高级别的隔离,但性能较差,因为每个事务执行时都会锁定相关数据表,阻止其他事务并发操作。
- 在这个隔离级别下,MVCC 不会发挥作用,所有的读写操作都会加锁,从而实现最强的一致性保证。
3.回滚日志(Undo Log)的作用
Undo Log 是 MVCC 机制的核心,负责存储数据的历史版本,用于支持读操作以及事务回滚。
3.1Undo Log 的生成
每当事务修改数据时,InnoDB 会将数据的旧版本写入 Undo Log,新的数据版本会记录在表的物理存储中。此时,旧版本数据通过roll_pointer 与新版本关联,形成一个链表结构。
3.2Undo Log 的回收
当没有事务需要访问 Undo Log 中的历史版本时,InnoDB 的后台线程会定期清理这些不再需要的日志。这一过程称为Purge,通过回收旧数据版本,避免系统中的存储开销过大。
4.MVCC 的优点和缺点
4.1优点
- 高并发性:通过快照读,多个事务可以并发执行读操作,而不需要加锁,减少了读写锁竞争,显著提高并发性能。
- 避免锁等待:由于读操作不需要加锁,减少了读写事务之间的锁等待,提高了系统吞吐量。
- 一致性保证:在较高的事务隔离级别(如可重复读)下,MVCC 保证了读到的数据的一致性,同时不会牺牲并发性。
4.2缺点
- 存储开销:由于需要存储多个版本的数据以及回滚日志,可能会导致存储空间的浪费,尤其是在长时间运行的事务中,旧版本数据占用的空间越来越大。
- 回滚日志的管理:回滚日志的生成和清理会增加系统负担,影响数据库的性能。特别是在长事务下,回滚日志可能会变得很大,影响系统的正常运行。
- 长事务的影响:如果一个事务持续时间过长,它持有的快照和 Undo Log 会阻止系统清理旧数据版本,导致数据库性能下降。
总结
MySQL 的 MVCC 机制是为了在高并发环境下提高性能和一致性的一种实现方案。它通过维护数据的多个版本和使用回滚日志,实现读写事务的并发操作,避免加锁的性能瓶颈。虽然 MVCC 在大多数场景下能提供高效的事务管理,但也有其局限性,特别是在长事务或大量修改操作的场景下,需要合理的事务管理策略和性能调优。

1464
2233


















































