InnoDB
是一个多版本存储引擎。它保留了旧版本行的信息,以支持事务特性,如并发和回滚。这些信息存储在撤销表空间中,称为回滚段。见 第 17.6.3.4 节,“撤销表空间”。InnoDB
使用回滚段中的信息来执行事务回滚所需的撤销操作。它还使用这些信息来构建行的早期版本,以实现一致的读取。见 第 17.7.2.3 节,“一致的非锁定读取”。
在内部,InnoDB
将三个字段添加到数据库中的每一行:
-
一个 6 字节的
DB_TRX_ID
字段,指示最后一个事务标识符,该事务插入或更新了该行。删除也被视为更新,其中一个特殊位被设置为标记为删除。 -
一个 7 字节的
DB_ROLL_PTR
字段,称为回滚指针。回滚指针指向撤销日志记录,该记录写入撤销表空间。如果行被更新,撤销日志记录包含重建行内容之前的信息。 -
一个 6 字节的
DB_ROW_ID
字段,包含一个行 ID,该 ID 按照新行的插入顺序单调递增。如果InnoDB
自动生成聚簇索引,该索引将包含行 ID 值。否则,DB_ROW_ID
列不会出现在任何索引中。
撤销日志在撤销表空间中被分为插入撤销日志和更新撤销日志。插入撤销日志仅在事务回滚时需要,并且可以在事务提交后被丢弃。更新撤销日志也用于一致的读取,但它们只能在没有事务需要 InnoDB
分配快照时被丢弃,以便在一致的读取中构建数据库行的早期版本。有关撤销日志的更多信息,请见 第 17.6.6 节,“撤销日志”。
建议您定期提交事务,包括只读事务。否则,InnoDB
无法丢弃更新撤销日志中的数据,撤销表空间可能会变得太大,填充撤销表空间。有关管理撤销表空间的信息,请见 第 17.6.3.4 节,“撤销表空间”。
撤销日志记录在撤销表空间中的物理大小通常小于相应的插入或更新行。您可以使用这些信息来计算撤销表空间所需的空间。
在 InnoDB
多版本控制方案中,行不会在您使用 SQL 语句删除时立即从数据库中物理删除。InnoDB
只有在丢弃更新撤销日志记录时才物理删除相应的行和索引记录。这项操作称为清除,通常需要与删除语句相同的时间。
如果您在表中以小批量插入和删除行,purge 线程可能会落后,表会变得越来越大,因为所有的“死”行,使得一切都变慢。在这种情况下,限制新行操作,并通过调整 innodb_max_purge_lag
系统变量来分配更多资源给 purge 线程。有关更多信息,请见 第 17.8.9 节,“清除配置”。
InnoDB
多版本并发控制(MVCC)对次要索引的处理方式不同于聚簇索引。聚簇索引记录在原地更新,并且它们的隐藏系统列指向撤销日志条目,以便重建记录的早期版本。与聚簇索引记录不同,次要索引记录不包含隐藏系统列,也不在原地更新。
当辅助索引列被更新时,旧的辅助索引记录被标记为删除,新的记录被插入,并且标记为删除的记录最终被清除。当辅助索引记录被标记为删除或辅助索引页被更新时,由于较新的事务,InnoDB
在聚簇索引中查找数据库记录。在聚簇索引中,记录的 DB_TRX_ID
被检查,并从 undo 日志中检索记录的正确版本,如果记录在读取事务启动后被修改。
如果辅助索引记录被标记为删除或辅助索引页被更新时,由于较新的事务,不使用 覆盖索引 技术。相反,InnoDB
在聚簇索引中查找记录。
然而,如果 索引条件下推 (ICP) 优化被启用,并且 WHERE
条件的一部分可以仅使用索引中的字段来评估,那么 MySQL 服务器仍然将该部分 WHERE
条件下推到存储引擎中,在那里使用索引来评估。如果没有找到匹配的记录,聚簇索引查找被避免。如果找到匹配的记录,即使是在标记为删除的记录中,InnoDB
也会在聚簇索引中查找记录。