InnoDB存储引擎对MVCC的实现
MVCC 是一种并发控制机制,用于在多个并发事件同时读写数据库时保持数据的同等性和隔离性。它是通过在每个数据行上维护多个版本的数据来实现的。当一个事件要对数据库中的数据进行修改时,MVCC 会为该事件创建一个数据快照,而不是直接修改现实的数据行。读操作(SELECT):
当一个事件执行读操作时,它会使用快照读取。快照读取是基于事件开始时数据库中的状态创建的,因此事件不会读取其他事件尚未提交的修改。具体工作情况如下:
[*]对于读取操作,事件会查找符合条件的数据行,并选择符合其事件开始时间的数据版本进行读取。
[*]如果某个数据行有多个版本,事件会选择不晚于其开始时间的最新版本,确保事件只读取在它开始之前已经存在的数据。
[*]事件读取的是快照数据,因此其他并发事件对数据行的修改不会影响当前事件的读取操作。
写操作(INSERT、UPDATE、DELETE):
当一个事件执行写操作时,它会生成一个新的数据版本,并将修改后的数据写入数据库。具体工作情况如下:
[*]对于写操作,事件会为要修改的数据行创建一个新的版本,并将修改后的数据写入新版本。
[*]新版本的数据会带有当前事件的版本号,以便其他事件可以或许精确读取相应版本的数据。
[*]原始版本的数据仍然存在,供其他事件使用快照读取,这保证了其他事件不受当前事件的写操作影响。
事件提交和回滚:
[*]当一个事件提交时,它所做的修改将成为数据库的最新版本,而且对其他事件可见。
[*]当一个事件回滚时,它所做的修改将被撤销,对其他事件不可见。
事件提交和回滚:
[*]当一个事件提交时,它所做的修改将成为数据库的最新版本,而且对其他事件可见。
[*]当一个事件回滚时,它所做的修改将被撤销,对其他事件不可见。
版本的采取:
为了防止数据库中的版本无限增长,MVCC 会定期进行版本的采取。采取机制会删除已经不再需要的旧版本数据,从而释放空间。
MVCC 通过创建数据的多个版本和使用快照读取来实现并发控制。读操作使用旧版本数据的快照,写操作创建新版本,并确保原始版本仍然可用。如许,不同的事件可以在肯定程度上并发执行,而不会相互干扰,从而进步了数据库的并发性能和数据同等性。
事件 ID 与 Undo 日志
在 InnoDB 中,每个事件在启动时都会被分配一个唯一的事件 ID。这个事件 ID 在 MVCC 的实现中起着关键作用。当对数据进行修改时,InnoDB 会将旧版本的数据记录到 Undo 日志中。
Undo 日志是一种用于存储数据修改前版本的机制。例如,当一个事件执行 UPDATE 操作时,它会先将原数据写入 Undo 日志,这个操作伴随着一个新的数据版本的创建。对于每个数据行,InnoDB 存储引擎通过一个隐藏的列来记录指向 Undo 日志中旧版本数据的指针。如许,在执行快照读时,可以根据事件开始的时间以及这些指针找到合适的旧版本数据。
同等性视图(Read View)的构建
当一个事件开始执行读操作时,InnoDB 会为该事件创建一个同等性视图。这个同等性视图决定了事件可以或许看到哪些版本的数据。
同等性视图中包罗了当前体系中活跃事件的列表(尚未提交的事件)。通过比力数据行的版本信息(包罗创建版本号和删除版本号)和同等性视图中的活跃事件列表,可以确定某个数据版本对于当前读事件是否可见。如果数据行的创建版本号小于当前事件的 ID,而且删除版本号大于当前事件的 ID 或者未界说(表示数据未被删除),那么这个数据版本对于当前事件是可见的。这种机制确保了事件可以或许基于一个稳定的、符合隔离级别的数据视图进行读取操作。
MVCC 与不同隔离级别
InnoDB 的 MVCC 在不同的隔离级别下有不同的表现:
[*]读已提交(Read Committed)隔离级别
在这个隔离级别下,每个 SELECT 语句都会重新创建一个同等性视图。这意味着一个事件在执行多次相同的 SELECT 语句时,大概会看到不同的数据版本。例如,在事件执行期间,如果另一个并发事件提交了对某些数据的修改,后续的 SELECT 操作大概会看到这些新提交的数据,由于新的同等性视图会反映最新的已提交事件的情况。
[*]可重复读(Repeatable Read)隔离级别
在可重复读隔离级别下,事件在启动时创建的同等性视图在整个事件期间保持稳定。这保证了事件在多次执行相同的 SELECT 语句时,看到的数据始终是同等的。即使其他并发事件对数据进行了修改并提交,当前事件也不会看到这些变革,直到它本身重新开始一个新的事件。这种特性使得可重复读隔离级别在需要稳定数据视图的场景中非常有用,例如在一些对数据同等性要求较高的业务逻辑中。
版本采取的机遇与计谋
版本采取是 MVCC 实现中紧张的一环,它涉及到数据库空间的有用使用。InnoDB 存储引擎采用了多种计谋来确定何时采取版本。
一种常见的计谋是基于 Undo 日志的大小和使用情况。当 Undo 日志占用的空间到达肯定阈值时,体系会触发版本采取操作。在采取过程中,会根据数据行的版本信息以及当前活跃事件的情况来判断哪些旧版本数据可以被安全地删除。例如,如果某个数据行的旧版本所关联的事件都已经提交而且不再有其他事件需要读取该旧版本,那么这个旧版本数据就可以被采取。此外,InnoDB 还会思量体系的负载情况,在体系负载较低的时间段更积极地进行版本采取,以镌汰对正常业务操作的影响。
通过对这些底层细节的理解,我们可以更好地把握 InnoDB 存储引擎中 MVCC 的工作原理,从而在数据库设计、优化以及故障排查等方面做出更合理的决议,进步数据库体系的整体性能和可靠性。同时,MVCC 的这种实现方式也为处理高并发数据库操作提供了一种优雅且高效的解决方案,平衡了数据同等性和并发性能之间的关系。
同等性非锁定读
对于 同等性非锁定读(Consistent Nonlocking Reads)的实现,通常做法是加一个版本号或者时间戳字段,在更新数据的同时版本号 + 1 或者更新时间戳。查询时,将当前可见的版本号与对应记录的版本号进行比对,如果记录的版本小于可见版本,则表示该记录可见
在 InnoDB 存储引擎中,多版本控制 (multi versioning) 就是对非锁定读的实现。如果读取的行正在执行 DELETE 或 UPDATE 操作,这时读取操作不会去等待行上锁的释放。相反地,InnoDB 存储引擎会去读取行的一个快照数据,对于这种读取历史数据的方式,我们叫它快照读 (snapshot read)
在 Repeatable Read 和 Read Committed 两个隔离级别下,如果是执行普通的 select 语句(不包括 select ... lock in share mode ,select ... for update)则会使用 同等性非锁定读(MVCC)。而且在 Repeatable Read 下 MVCC 实现了可重复读和防止部分幻读
锁定读
如果执行的是下列语句,就是 锁定读(Locking Reads)
[*]select ... lock in share mode
[*]select ... for update
[*]insert、update、delete 操作
在锁定读下,读取的是数据的最新版本,这种读也被称为 当前读(current read)。锁定读会对读取到的记录加锁:
[*] select ... lock in share mode:对记录加 S 锁,别的事件也可以加S锁,如果加 x 锁则会被壅闭
[*] select ... for update、insert、update、delete:对记录加 X 锁,且别的事件不能加任何锁
在同等性非锁定读下,即使读取的记录已被别的事件加上 X 锁,这时记录也是可以被读取的,即读取的快照数据。上面说了,在 Repeatable Read 下 MVCC 防止了部分幻读,这边的 “部分” 是指在 同等性非锁定读 情况下,只能读取到第一次查询之前所插入的数据(根据 Read View 判断数据可见性,Read View 在第一次查询时生成)。但是!如果是 当前读 ,每次读取的都是最新数据,这时如果两次查询中心有别的事件插入数据,就会产生幻读。以是, InnoDB 在实现Repeatable Read 时,如果执行的是当前读,则会对读取的记录使用 Next-key Lock ,来防止别的事件在间隙间插入数据
Read View
[*]Read View 是事件在执行查询操作时生成的一个视图,用于确定哪些版本的数据对该事件可见。Read View 中包罗了以下几个紧张信息:
[*]m_ids:表示当前体系中活跃的事件 ID 列表。
[*]min_trx_id:表示当前体系中活跃的最小事件 ID。
[*]max_trx_id:表示下一个将要分配的事件 ID。
[*]creator_trx_id:表示创建该 Read View 的事件 ID。
[*]当事件执行查询操作时,InnoDB 会根据 Read View 来判断数据的可见性。具体规则如下:
[*]如果数据的DB_TRX_ID小于min_trx_id,说明该数据在当前事件开始之前就已经提交,因此对当前事件可见。
[*]如果数据的DB_TRX_ID大于max_trx_id,说明该数据是在当前事件开始之后才生成的,因此对当前事件不可见。
[*]如果数据的DB_TRX_ID在min_trx_id和max_trx_id之间,而且不在m_ids列表中,说明该数据已经提交,对当前事件可见。
[*]如果数据的DB_TRX_ID在m_ids列表中,说明该数据是由当前活跃的事件生成的,对当前事件不可见
InnoDB 存储引擎对 MVCC 的实现主要包括以下几个关键部分:
[*]隐藏字段:InnoDB 表中的每行数据包罗DB_TRX_ID和DB_ROLL_PTR等隐藏字段,DB_TRX_ID记录插入或更新该行数据的事件 ID,DB_ROLL_PTR指向该行数据的旧版本,形成版本链。
[*]Undo 日志:用于记录数据修改前的状态,事件修改数据时先将原始数据写入 Undo 日志,其记录按事件提交次序构造成链,可用于回滚事件和查询数据旧版本。
[*]Read View:事件执行查询时生成的视图,包罗m_ids、min_trx_id、max_trx_id和creator_trx_id等信息,用于确定数据的可见性,依据特定规则判断数据对当前事件是否可见。
[*]版本链与数据查询:查询时从当前行数据出发,沿版本链查找符合 Read View 可见性规则的版本,找到则返回对应数据,找不到则返回空结果。
[*]事件提交与清理:事件提交时标记其 Undo 日志记录为已提交并释放资源,同时按计谋清理不再需要的旧版本数据,以节省存储空间。通过这些机制,InnoDB 实现了 MVCC,进步了数据库的并发性能。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]