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




