InnoDB 是一个多版本存储引擎。它保留已更改行的旧版本信息,以支持诸如并发性和回滚等事务功能。这些信息存储在称为回滚段的数据结构中的撤销表空间中。请参见 第 17.6.3.4 节,“撤销表空间”。InnoDB 使用回滚段中的信息来执行事务回滚中所需的撤销操作。它还使用这些信息来构建行的早期版本,以实现一致性读取。请参见 第 17.7.2.3 节,“一致的非锁定读取”。InnoDB is a multi-version storage engine. It
keeps information about old versions of changed rows to support
transactional features such as concurrency and rollback. This
information is stored in undo tablespaces in a data structure called
a rollback segment. See Section 17.6.3.4, “Undo Tablespaces”.
InnoDB uses the information in the rollback
segment to perform the undo operations needed in a transaction
rollback. It also uses the information to build earlier versions of
a row for a consistent read. See
Section 17.7.2.3, “Consistent Nonlocking Reads”.
在内部,InnoDB 向存储在数据库中的每一行添加三个字段:Internally, InnoDB adds three fields to each row
stored in the database:
一个 6 字节的
DB_TRX_ID字段,用于表示插入或更新该行的最后一个事务的事务标识符。此外,删除在内部被视为一种更新,在这种更新中行中的一个特殊位被设置,用于标记该行已被删除。A 6-byteDB_TRX_IDfield indicates the transaction identifier for the last transaction that inserted or updated the row. Also, a deletion is treated internally as an update where a special bit in the row is set to mark it as deleted.一个 7 字节的
DB_ROLL_PTR字段,称为回滚指针。回滚指针指向写入回滚段的撤销日志记录。如果该行被更新,撤销日志记录包含重建行在更新前内容所需的信息。A 7-byteDB_ROLL_PTRfield called the roll pointer. The roll pointer points to an undo log record written to the rollback segment. If the row was updated, the undo log record contains the information necessary to rebuild the content of the row before it was updated.一个 6 字节的
DB_ROW_ID字段包含一个随着新行插入而单调增加的行 ID。如果InnoDB自动生成聚簇索引,则该索引包含行 ID 值。否则,DB_ROW_ID列不会出现在任何索引中。A 6-byteDB_ROW_IDfield contains a row ID that increases monotonically as new rows are inserted. IfInnoDBgenerates a clustered index automatically, the index contains row ID values. Otherwise, theDB_ROW_IDcolumn does not appear in any index.
回滚段中的撤销日志分为插入撤销日志和更新撤销日志。插入撤销日志仅在事务回滚时需要,并且在事务提交后可以立即丢弃。更新撤销日志也用于一致性读,但只有在不存在事务使用InnoDB分配的快照,而在一致性读中可能需要更新撤销日志中的信息来构建数据库行的早期版本时,才可以丢弃。有关撤销日志的更多信息,请参见第 17.6.6 节,“撤销日志”。Undo logs in the rollback segment are divided into insert and update
undo logs. Insert undo logs are needed only in transaction rollback
and can be discarded as soon as the transaction commits. Update undo
logs are used also in consistent reads, but they can be discarded
only after there is no transaction present for which
InnoDB has assigned a snapshot that in a
consistent read could require the information in the update undo log
to build an earlier version of a database row. For additional
information about undo logs, see Section 17.6.6, “Undo Logs”.
建议您定期提交事务,包括仅执行一致性读的事务。否则,InnoDB无法丢弃更新撤销日志中的数据,回滚段可能会过大,从而填满其所在的撤销表空间。有关管理撤销表空间的信息,请参见第 17.6.3.4 节,“撤销表空间”。It is recommend that you commit transactions regularly, including
transactions that issue only consistent reads. Otherwise,
InnoDB cannot discard data from the update undo
logs, and the rollback segment may grow too big, filling up the undo
tablespace in which it resides. For information about managing undo
tablespaces, see Section 17.6.3.4, “Undo Tablespaces”.
回滚段中撤消日志记录的物理大小通常比相应的插入或更新行小。您可以使用此信息来计算回滚段所需的空间。The physical size of an undo log record in the rollback segment is typically smaller than the corresponding inserted or updated row. You can use this information to calculate the space needed for your rollback segment.
在 InnoDB 多版本方案中,当您使用 SQL 语句删除一行时,行并不会立即从数据库中物理删除。InnoDB 仅在丢弃为删除操作写入的更新撤消日志记录时才会物理删除相应的行及其索引记录。这种删除操作称为清理(purge),速度相当快,通常与执行删除的 SQL 语句所需的时间在同一数量级。In the InnoDB multi-versioning scheme, a row is
not physically removed from the database immediately when you delete
it with an SQL statement. InnoDB only physically
removes the corresponding row and its index records when it discards
the update undo log record written for the deletion. This removal
operation is called a purge, and it is quite fast, usually taking
the same order of time as the SQL statement that did the deletion.
如果您以大约相同的速度在表中批量插入和删除行,清理线程可能会开始滞后,表会因为所有的 “死” 行而变得越来越大,使所有操作受制于磁盘,速度非常慢。在这种情况下,应限制新行操作的速度,并通过调整 innodb_max_purge_lag 系统变量,为清理线程分配更多资源。更多信息请参见 第 17.8.9 节,“清理配置”。If you insert and delete rows in smallish batches at about the same
rate in the table, the purge thread can start to lag behind and the
table can grow bigger and bigger because of all the
“dead” rows, making everything disk-bound and very
slow. In such cases, throttle new row operations, and allocate more
resources to the purge thread by tuning the
innodb_max_purge_lag system
variable. For more information, see
Section 17.8.9, “Purge Configuration”.
InnoDB 多版本并发控制(MVCC)对二级索引的处理方式不同于聚簇索引。聚簇索引中的记录是就地更新的,它们的隐藏系统列指向撤销日志条目,从中可以重建记录的早期版本。与聚簇索引记录不同,二级索引记录不包含隐藏系统列,也不会就地更新。InnoDB multiversion concurrency control (MVCC)
treats secondary indexes differently than clustered indexes.
Records in a clustered index are updated in-place, and their
hidden system columns point undo log entries from which earlier
versions of records can be reconstructed. Unlike clustered index
records, secondary index records do not contain hidden system
columns nor are they updated in-place.
当次级索引列被更新时,旧的次级索引记录会被标记为删除,新记录会被插入,而被标记删除的记录最终会被清除。当次级索引记录被标记为删除或者次级索引页被更新为较新的事务时,InnoDB 会在聚簇索引中查找数据库记录。在聚簇索引中,会检查记录的 DB_TRX_ID,如果记录在读取事务启动后被修改,则会从撤销日志中检索该记录的正确版本。When a secondary index column is updated, old secondary index
records are delete-marked, new records are inserted, and
delete-marked records are eventually purged. When a secondary
index record is delete-marked or the secondary index page is
updated by a newer transaction, InnoDB looks up
the database record in the clustered index. In the clustered
index, the record's DB_TRX_ID is checked, and
the correct version of the record is retrieved from the undo log
if the record was modified after the reading transaction was
initiated.
如果某个二级索引记录被标记为删除,或者二级索引页被较新的事务更新,则不会使用覆盖索引技术。InnoDB不会从索引结构中返回值,而是会在聚簇索引中查找记录。If a secondary index record is marked for deletion or the
secondary index page is updated by a newer transaction, the
covering index
technique is not used. Instead of returning values from the index
structure, InnoDB looks up the record in the
clustered index.
但是,如果启用了索引条件下推 (ICP)优化,并且WHERE 条件的部分可以仅使用索引中的字段进行评估,MySQL 服务器仍然会将这一部分WHERE条件下推到存储引擎,在那里使用索引进行评估。如果没有找到匹配的记录,则可以避免聚簇索引查找。如果找到了匹配的记录,即使是在标记为删除的记录中,InnoDB也会在聚簇索引中查找该记录。However, if the
index
condition pushdown (ICP) optimization is enabled, and parts
of the WHERE condition can be evaluated using
only fields from the index, the MySQL server still pushes this
part of the WHERE condition down to the storage
engine where it is evaluated using the index. If no matching
records are found, the clustered index lookup is avoided. If
matching records are found, even among delete-marked records,
InnoDB looks up the record in the clustered
index.