InnoDB 在每行数据中增加了三个字段:
- DB_TRX_ID 占用6个字节. 记录最近插入或修改这行数据的事务id. 删除操作也算作更新操作, 因为删除操作只是更新了一个内部的bit, 把数据标识为删除
DB_ROLL_PTR 占用7个字节. 被叫做回滚指针(roll pointer). 回滚指针指向 rollback segment 中的undo log记录. 如果记录被更新 DB_ROLL_PTR 包含重建旧版本数据的必要信息.
DB_ROW_ID 占用6个字节. 包含自增的row id. 如果 InnoDB 自动创建了聚簇索引, 聚簇索引中将会包含这个 row ID值; 否则 DB_ROW_ID 不会出现在任何索引中
如果记录被更新 DB_ROLL_PTR 包含重建旧版本数据的必要信息. 是什么信息呢?
猜测指向上一次修改记录的undo log.
在 rollback segment 中的undo log分为insert和update两种. insert undo log 只被用在事务回滚阶段, 可以在事务提交后马上删除. update undo log 不仅在回滚时被用到, 也在一致性读中被用到.update undo log 可以在不会被当前事务使用到来重建老版本数据时被删除(也许是没有事务id小于undo log 中的事务id时?). undo-log
因此, 需要经常地提交事务, 包括只读事务. 否则innodb不能删除这些update undo log数据, rollbakc segment 也许会变得太大, 最终填满 undo tablespace.undo tablespace
在InnoDB中, 一行数据不会马上被物理删除. InnoDB 只会在删除这些数据的undo log 被删除时, 删除这些数据和相关的索引记录. 这个删除操作被叫做 purge, purge 操作很快.
对次要索引的影响
MVCC 对聚簇索引和次要索引的处理方式不同
聚簇索引中的数据会被就地(in-place)更新, 并且在聚簇索引中包含重建较早版本数据的必要信息. 次要索引中不包含这些信息, 因此仅凭次要索引不能重建较早版本的数据, 并且次要索引也不会被就地更新.
当一个次要索引被更新的时候, 旧的索引记录被标记为删除, 新的数据会被插入; 被标记为删除的数据, 最终会被purge 操作删除.
当一个次级索引记录被标记为删除, 或者刺激索引页被更新的事务(事务id更大的数据)更新时, InnoDB 会去聚簇索引读取数据, 包括 DB_TRX_ID, 如果记录被更新的事务修改, 将重建老版本数据. 此时覆盖索引将不会生效.