Files
rikako-note/mysql/mysql文档/mysql_mvcc_impl.md
2025-08-13 17:08:13 +08:00

5.3 KiB
Raw Blame History

mysql mvcc

innodb是一个多版本的存储引擎对于被修改的records其保存了records旧版本的信息从而支持事务的并发回滚等特性。

innodb使用了rollback segment中存储的信息来进行undo操作,从而支持事务在需要时进行回滚;并且支持通过undo信息构建record的早期版本从而实现一致性读

Internal Impl

在innodb的内部实现中其为数据库中存储的每行数据都额外添加了3个字段

  • DB_TRX_ID长度为6字节用于标识最后对改行数据进行insert/update操作的事务
    • 其中delete操作也被看做是update因为innodb在对数据执行删除操作时并不会立马对数据进行物理删除而是会先标记该行数据的delete mark数据实际被物理删除发生在purge阶段
  • DB_ROLL_PTR长度为7字节被称为roll pointer。该指针指向undo record通过undo record中的内容可以构建该行数据被更新前的版本
  • DB_ROW_ID长度为6字节该字段包含一个row id该row id在数据被插入时会单调的增长。
    • 如果表使用的是innodb自动生成的聚簇索引未显式指定主键那么自动生成的聚簇索引将会包含该row id的值
    • 如果表显式指定了聚簇索引,那么DB_ROW_ID并不会出现在任何索引中

undo log

在rollback segment中undo log可以分为两种类型

  • insert undo log
  • update undo log

insert undo log

insert undo log只会在事务回滚时被用到在事务提交之后insert undo log的内容可以被立马删除。

update undo log

update undo log除了用于事务回滚外还用于一致性读MVCC。对于update undo log其只在满足如下条件时可以被删除

  • 需要通过该update undo log来构建数据先前版本的事务都不存在时update undo log才可以被删除

innodb会为每个事务分配一个快照事务在进行一致性读时实际读取的是快照中的旧版本数据。

快照需要通过update undo log来还原行数据的旧版本。如果没有事务再需要通过该update undo log来还原旧数据代表该update undo log可以被删除。

commit regularly

在编写和数据库交互的代码时,推荐周期性的提交事务,包括只会进行一致性读的读事务。如果事务A的运行时间较长且一直未提交那么在事务A运行时其他事务对数据库的更新操作其生成的update undo log在事务A运行期间都无法被丢弃因为有可能A会读取被修改数据之前的版本此时需要通过undo update log来进行旧版本数据的还原

故而如果存在一直不提交的事务那么可能会造成update undo log无法丢弃那么rollback segment占用的空间大小会不断增加填满其所位于的undo tablespace。

purge

在innodb的mvcc方案中在通过delete sql删除行数据后行数据并不会立马就从该数据库中被移除不会立马被物理删除

innodb直到删除update undo log record时删除undo log record关联的行数据/index records。该删除操作被称为purge

purge的操作很快并且purge的顺序通常和执行delete sql的时间顺序相同。

insert and delete rows in smallish batches

如果针对表同时执行insert和delete的小批量操作且insert和delete的速率相同那么purge现成的回收速率可能会小于数据的插入速率。这样会导致dead rows标记为逻辑删除但未实际purge的数据行堆积表占用空间越来越大并造成disk相关操作变慢。

在上述场景下应当限制新操作并且通过调整innodb_max_purge_lag向purge thread分配更多资源。

purge lag

innodb_purge_threads

purge操作在后台由一个或多个purge threads执行。purge threads的数量由innodb_purge_threads来进行控制,默认值的取值逻辑如下:

  • 如果可获取的逻辑核数小于等于16则默认值为1
  • 如果logic processors大于16那么默认值为4

当dml操作集中在一张表上那么该表的purge操作由一个现成来执行这样可能会造成purge操作变慢增加purge lag。

innodb_max_purge_lag

如果purge lag超过innodb_max_purge_lagpurge工作会自动在多个purge threads之间进行重新分配。

当purge threads设置过大时可能会造成与user threads的争用故而相当适当的管理purge threads大小。

innodb_max_purge_lag的默认值为0代表默认不存在max purge lag。

Multi-Versioning and Secondary Indexes

在mvcc中对待聚簇索引和辅助索引的方式不同。在聚簇索引中record中的列是update in-place并且其hidden system columns指向undo log records通过undo log records可以还原数据的先前版本。

但是辅助索引不包含hidden system columns并且对于辅助索引的更新也不是update in-place。

当辅助索引的column被更新时旧的辅助索引记录将会被标记为delete marked并且插入新的辅助索引记录。delete marked index records最终会被purge。

当辅助索引中的index record被delete marked辅助索引页被newer transaction(更新的事务)更新时innodb将会在聚簇索引中查询记录