MySQL面试问题:MySQL MVCC的实现原理

我们可以深入了解MySQL如何实现多版本并发控制(MVCC)的细节

photo by Dino Reichmuth on Unsplash

感谢您阅读这篇文章。更多面试问题:
https://programmerscareer.com/zh-cn/software-interview-set/

主题:解析 MVCC

多版本并发控制 (MVCC) 是数据库管理系统中使用的技术,用于处理多个用户同时访问同一数据而不发生冲突,从而提高处理效率。

简单来说,MVCC 允许多个事务同时访问同一数据而不发生冲突或需要读锁,这可能会严重影响性能。这是通过为事务创建数据的一个“快照”来实现的,其他并发事务不会影响这个快照。

现在,让我们分解一下术语 MVCC:

  • 多版本:这意味着数据库保存多个版本的同一行。版本是数据在某个时间点的一个快照。
  • 并发控制:这表明技术用于处理同时进行的事务,不发生冲突,确保每个事务都保持数据库的假象,就好像它是唯一访问数据库的。

MySQL 在其 InnoDB 存储引擎中实现了 MVCC。当事务更新 InnoDB 中的行时,原始行不会立即被覆盖或删除。相反,InnoDB 会存储更新前的旧版本,以便其他正在进行的事务可以看到原始版本。这就是数据行的多版本来源。

所以,为什么我们在 MySQL 中使用 MVCC?主要是性能原因。通过允许多个事务同时访问同一快照的数据,我们避免了读锁,这可能会严重影响性能,特别是在许多用户同时查询和更新同一数据库的情况下。

主题:MySQL 中的 MVCC 是如何工作的

让我们来详细地了解 MySQL 中的 MVCC 是如何工作的。

当事务在 MySQL (InnoDB) 中开始时,它会被分配一个唯一的事务 ID。这个 ID 用于创建事务的数据库视图。这个视图包含已提交数据的所有版本,直到事务开始时,并且包含事务自身所做的更改。事务不能看到其他并发事务所做的更改,这为其提供了一致的快照并确保隔离性。

当行被修改时,InnoDB 不会覆盖现有数据。相反,它会写入新行版本并保存旧版本的信息在一个名为撤销日志的区域中。这个日志包含需要反转更改的信息,如果事务被回滚,并且提供旧版本的行给其他事务,如果它们需要它们。

现在,让我们讨论一些相关的主题:读视图、撤销日志和清理。

读视图 是 InnoDB 使用的机制,用于实现一致的读取,即读取数据库的快照,与事务开始时相对应。

撤销日志 是 MVCC 的一个关键部分。当事务修改数据时,InnoDB 会写入新行并在撤销日志中存储需要反转更改的信息。如果其他事务需要看到旧版本的行,InnoDB 使用撤销日志中的信息来重构它们。

清理 与 InnoDB 如何清理不再需要的旧版本的行有关。一旦所有可能需要访问旧版本的行的事务都完成了,InnoDB 就可以释放这些版本所占用的空间。这个过程被称为清理。

主题:ACID 特性和 MVCC

在可靠的数据库管理系统中,维持 ACID 原则(Atomicity、Consistency、Isolation、Durability)是至关重要的方面之一。

  1. 原子性:如果事务包含多个操作,原子性意味着要么所有操作都成功执行,要么都不执行。事务不能部分完成。如果发生任何操作中的错误,整个事务将被回滚。
  2. 一致性:一致性意味着事务应该将数据库从一个一致状态转换到另一个一致状态,根据已定义的规则。例如,如果帐户没有足够的余额进行提款,则事务应该被拒绝以维持一致性。
  3. 隔离性:隔离性在多个事务同时执行时发挥作用。它意味着每个事务应该像是唯一一个事务一样执行。事务的中间状态不应该可见于其他事务。
  4. 持久性:持久性确保事务一旦提交,就会永久保存。换句话说,事务的结果是永久的。

MVCC (多版本并发控制) 与 ACID 特性相关,下面是详细的解释:

在 MySQL(特别是其 InnoDB 存储引擎)的上下文中,MVCC 提供了隔离和一致性。

隔离性 由每个事务使用其自身的数据库快照来保证。即使多个事务同时试图读写同一数据,每个事务也会看到其自身的一致快照,就好像它是唯一一个事务一样。

一致性 由 MVCC 中的回滚日志来维护。如果事务失败或回滚,则可以撤销该事务中的更改,以确保数据库处于一致状态。此外,通过为事务创建事务特定的数据视图,可以确保事务总是处理一致的数据集。

主题:快照读和当前读

在 MySQL 中,当 MVCC (多版本并发控制) 发挥作用时,有两种主要类型的读取操作:快照读和当前读。让我们详细了解这些概念。

快照读

快照读,就像名字所表明的,提供了数据库在事务开始时的一致快照。它不会看到其他并发执行的事务所做的更改。这种读取是默认模式下 SELECT 语句的。快照读是 MVCC 的核心,它为 MVCC 提供了“一致视图”的概念。

当前读

与快照读不同,当前读看到最新提交的数据,包括其他事务所做的更改。模式如 SELECT…FOR UPDATESELECT…LOCK IN SHARE MODE 使用当前读。它还用于当前事务所做的数据更改,例如 UPDATEINSERTDELETE

这两种类型的读取提供了事务处理数据的灵活方法。事务是否要看到数据库在事务开始时的状态,或者要看到最新数据,包括其他事务所做的更改,取决于使用哪种类型的读取。

主题:在 MySQL 中管理死锁

现在,让我们探讨 MySQL 的 MVCC 中的另一个关键方面——处理死锁。

死锁发生在两个或多个事务同时持有和请求锁时,创造了一个循环依赖,无法解决。 无处理,这些事务可能会永久等待,显然不是理想的。

MySQL 处理死锁的方法是使用等待图。简单地说,当事务 A 等待事务 B 释放行锁时,就在 A 和 B 之间添加一条边。 如果添加这条边创建了一个循环,则检测到死锁。

在检测到死锁后,MySQL 需要解决它。它通过选择一个事务作为“受害者”并回滚它来完成。 在大多数情况下,它选择已经做了最少工作的事务,以便少量的工作被丢弃。 回滚受害者事务后,死锁就被解决了。

在 MySQL 中,您可以使用 SHOW ENGINE INNODB STATUS; 来获取有关最近死锁的信息,这可以帮助调试。

死锁管理,尽管大多数自动,要谨慎地处理事务的设计和执行。建议尽可能地缩短事务并尽可能地提交它们,以减少死锁的可能性。

主题:MVCC 性能影响

尽管 MySQL 的 MultiVersion Concurrency Control (MVCC) 在内部为并发访问提供了许多好处,但要识别 MVCC 不是无价的。 让我们来探讨一些这些:

  1. 磁盘空间: 其中一个主要开销是增加的磁盘空间。 由于 MVCC 保存不同版本的行以提供隔离、一致的视图给事务,需要更多的磁盘空间。 这可能会在重读写混合的工作负载中显著。
  2. CPU 和 I/O 资源: 生成多版本的数据、维护它们并清理不必要的版本 (垃圾回收) 可能会耗费 CPU 和 I/O 资源。
  3. 锁定开销: 尽管 MVCC 减少了锁定,它并不完全消除了,特别是对写事务 (插入、更新、删除) 的锁定。 这些锁定增加了性能开销。
  4. 增加复杂性: MVCC 增加了数据库引擎的复杂性。 它需要管理多版本的数据、处理回滚、解决冲突和清理旧版本。 这种复杂性增加了整体性能的开销。

在哪些场景中可能考虑替代 MVCC?

虽然 MVCC 为多用户访问提供了出色的好处,但它可能不是每个场景的最佳选择。 例如,在大量写入一次并多次读取的应用程序中,可能更好地考虑 MyISAM 存储引擎,它不支持 MVCC。

此外,在要求绝对最新数据的应用程序中,也可能要考虑其他方法,因为 MVCC 提供了数据的“快照”,而不是最新版本。

要了解工作负载、性能期望和硬件资源可用性之前,就要考虑使用 MVCC 的决定。

主题:回并评估

现在,让我们回和总结 MySQL 中 MultiVersion Concurrency Control (MVCC) 的不同方面:

  1. MVCC 是数据库管理系统中用于处理并发事务的方法
  2. MVCC 在 MySQL 中提供每个事务的“快照”,允许多个事务同时读取(并写入)同一数据项,大大提高了数据库的性能和可伸缩性。
  3. 快照读和当前读是 MySQL 中 MVCC 的两个关键概念。快照读提供事务开始时数据的一致视图,并确保事务使用了一致的数据状态。当前读是指考虑其他事务已提交的最新数据的一种读取方式。
  4. MVCC 与数据库的 ACID 属性密切相关,确保事务的原子性、一致性、隔离性和持久性。
  5. MVCC 在 MySQL 中处理死锁,这是两个事务等待对方释放资源的情况。
  6. 虽然 MVCC 提供了许多优势,但它也不是完全免费的,例如增加磁盘空间和 CPU 使用量。

这些是我们在 MySQL 中讨论 MVCC 的多个方面。现在,就是时候评估你的理解了。考虑以下问题:

  • MVCC 如何在 MySQL 中提高并发事务?
  • MySQL 中 MVCC 的快照读和当前读有什么区别?
  • MVCC 在 MySQL 中是如何处理死锁的?
  • MVCC 在使用时会带来哪些性能交换?

思考这些问题。您可以在纸上写下回答或者简单地为自我评估思考。


  1. MVCC 通过允许多个用户同时访问同一行的表来提高并发事务。每个事务都会获取数据的一致状态,在事务开始时。
  2. 在 MySQL 中,快照读和当前读是两种不同的读取隔离级别。快照读是指事务读取数据库状态的一致快照,确保事务内部的数据一致性。当前读是指考虑其他事务已提交的最新数据的一种读取方式。
  3. MVCC 在 MySQL 中处理死锁通过 wait-for 图来处理。当一个事务等待另一个事务释放锁时,会在 wait-for 图中添加一条边。如果添加这条边创造了一个循环,则会检测到死锁。MySQL 会选择一个事务作为“受害者”并回滚它来解决死锁。
  4. MVCC 与数据库的 ACID 属性密切相关,确保事务的原子性、一致性、隔离性和持久性。

English post: https://programmerscareer.com/mysql-interview17/
作者:Wesley Wei – Twitter Wesley Wei – Medium
注意:本文为作者原创,转载请注明出处。

MySQL面试问题:MySQL常用的存储引擎有哪些?有什么区别? MySQL面试问题:什么时候分割数据库,什么时候分割表?

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×