InnoDB-MVCC

多用户,事务,回滚与持久化

三个额外域

名称 长度/Byte 用途
DB_TRX_ID 6 最后插入/修改该行的事务ID
DB_ROLL_PTR 7 历史数据(undo log)指针
DB_ROW_ID 6 自增行号,只在使用默认自增的时候才会出现

此外,还有一个删除标志位,用于表示数据已被删除,然而并没有写该标志位的具体位置,需要看看源码

Undo Logs

Undo logs有两种,insert undo logs & update undo logs

insert undo logs

仅用于事务回滚,且在事务提交后就可以回收。有点疑惑具体的使用场景

update undo logs

用于一致性读,但是只有在没有事务会读到该数据的前提下才能回收。主要用于提供不同时间点的快照

Notice

周期性将事务提交是一个好习惯,否则InnoDB不知道现在应该回收哪些数据,进而可能导致rollback segment太大

Space

undo log所占空间一般比常规的行要小,具体计算方法未知

Delete

在InnoDB的MVCC中,删除行时只会加上一个标志位,并不是马上就物理删除的,只有在没有事务会再读到该数据时,才会用非常快的速度将其从rollback segment物理删除(purge)。具体的触发条件是,删除该行的update undo log被回收的时候,进行purge操作。
注意,以保证服务质量,purge线程只有在没有数据写入的情况下运行,所以如果边写边删,purge线程将会一直被延迟执行,最终导致数据库会越来越大。具体延迟时间,通过参数innodb_max_purge_lag调整。

MVCC和辅助索引

主索引进行更新的时候,如前文所示,会将当前数据拷贝到rollback segment中,再原地修改当前的数据。由于辅助索引不具备TRX_ID等额外列,所以做不到原地修改的效果。

辅助索引修改流程

  1. 旧索引项被标记为删除
  2. 插入新索引
  3. 删除旧索引

删除时被访问

当被标记删除的索引项被访问到时,InnoDB会先去找主索引,再检查上文中的那一堆DB_TRX_ID等。如果DB_TRX_ID不对,则会放弃使用辅助索引,直接去主索引里面找(遍历)

查询优化

当Index Condition Pushdown优化被打开时,而且刚好Where项里的内容能够用索引找到,MySQL上层服务会直接把整个Where语句推给底层的InnoDB引擎,InnoDB会先去索引里面找有没有符合项,如果没有,那就认为这个Where啥也没选中,返回空;如果找到了,即使被标记为删除,InnoDB还是会去主索引里面再确认一下DB_TRX_ID和其他使用该辅助索引无法确定的判断条件等信息。

ref