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
仅在丢弃为删除操作写入的更新撤消日志记录时,才会物理删除相应的行及其索引记录。此删除操作称为清除,它非常快,通常与执行删除操作的 SQL 语句花费的时间相同。
如果您以大致相同的速率在表中以小批量插入和删除行,则清除线程可能会开始滞后,并且由于所有““死””行,表可能会变得越来越大,从而导致所有操作都与磁盘绑定并且非常慢。在这种情况下,请限制新行操作,并通过调整 innodb_max_purge_lag
系统变量为清除线程分配更多资源。有关更多信息,请参阅 第 17.8.9 节“清除配置”。
InnoDB
多版本并发控制 (MVCC) 处理辅助索引的方式与处理聚集索引的方式不同。聚集索引中的记录会原地更新,并且其隐藏的系统列指向撤消日志条目,可以从这些条目重建记录的早期版本。与聚集索引记录不同,辅助索引记录不包含隐藏的系统列,也不会原地更新。
当二级索引列被更新时,旧的二级索引记录会被标记为删除,新的记录会被插入,并且标记为删除的记录最终会被清除。当一个二级索引记录被标记为删除或二级索引页被更新的事务更新时,InnoDB
会在聚集索引中查找数据库记录。在聚集索引中,会检查记录的 DB_TRX_ID
,如果记录在读取事务启动后被修改,则从撤销日志中检索记录的正确版本。
如果一个二级索引记录被标记为删除或二级索引页被更新的事务更新,则不会使用覆盖索引技术。 InnoDB
不会从索引结构返回数值,而是在聚集索引中查找记录。
但是,如果启用了索引条件下推 (ICP) 优化,并且 WHERE
条件的部分内容可以使用仅来自索引的字段进行评估,则 MySQL 服务器仍然会将这部分 WHERE
条件下推到使用索引进行评估的存储引擎。如果没有找到匹配的记录,则避免了聚集索引查找。如果找到了匹配的记录,即使在标记为删除的记录中,InnoDB
也会在聚集索引中查找记录。