InnoDB官方文档--14.3 InnoDB的多版本
14.3 InnoDB的多版本
InnoDB是一个多版本存储引擎:它会保留关于行变动的旧版本信息用来支持事务特性,例如并发和回滚(rollback).这些信息被称为回滚段(rollback segment),存储在表空间中.InnoDB使用回滚段中的信息来执行事务回滚中所需要的撤销操作.还使用该信息构建早期版本以进行一致的行读取.
在内部,InnoDB为存储在数据库的每一行添加三个字段.一个6位的DB_TRX_ID
字段用来标识插入或更新行的最后一个事务.此外,删除在内部被视为更新,行的一个特殊位用来标记是否删除.每一行还包含一个7位的DB_ROLL_PTR
字段叫做滚动指针(roll pointer).滚动指针指向写入回滚段的撤消日志记录.如果行被更新了,那么撤消日志记录了用来重建被更新之前的行内容所必要的信息.一个6位的DB_ROW_ID
字段包含了一个行ID在插入的时候递增.如果InnoDB自动生成聚簇索引,这个索引会包含行ID的值.否则,DB_ROW_ID
列不会出现在任何索引中.
回滚段中的撤销日志分为插入和更新的撤销日志(undo logs).插入的回滚日志只在事务回滚的时候需要并且在事务提交之后可以立即丢弃.更新的撤销日志也被用于一致性读,但是只有在InnoDB没有分配快照的事务之后才能丢弃它们,在一致读取中可能需要更新撤消日志中的信息来构建数据库行的早期版本.
定期提交你的事务,包括那些只有一致性读的事务.否则,InnoDB将不能从更新的撤销日志里丢弃数据使得回滚段变得过大而填满表空间.
回滚段中撤消日志记录的物理大小通常小于相应的插入或更新行.你可以使用此信息计算回滚段所需的空间.
在InnoDB多版本方案中,当你使用sql语句删除行的时候不会马上从数据库中物理删除.InnoDB只在丢弃为删除而写的更新撤销日志的时候才会物理的删除相应的行.这个删除操作叫做清除(purge),它很快,通常采用和sql语句删除时相同的顺序.
如果你在表中以相同的速率执行小批量的插入和删除操作,清除线程可能开始落后,因为那些”死掉”的行,表会变得越来越大,使得一切都受磁盘限制变得很慢.在这种情况下,通过调整innodb_max_purge_lag系统变量来限制新行操作,并为清除线程分配更多资源.
多版本和二级索引
InnoDB的多版本并发控制(MVCC)看待二级索引和聚簇索引是不同的.聚簇索引中的记录更新是立即的,它们的隐藏系统列指向撤消日志条目,从中可以重建早期版本的记录.与聚簇索引记录不同,二级索引记录不包含隐藏的系统列,也不会立即更新.
当一个二级索引列被更新的时候,旧的二级索引记录会被标记删除,新的记录插入,最终清除被标记删除的记录.当一个二级索引记录被标记删除或二级索引页面被一个新事务更新的时候,InnoDB在聚合索引中查找数据库记录.在聚合索引中,记录的DB_TRX_ID会被检查并且记录的正确版本会从撤销日志中恢复如果在读事务开始之后记录被修改的话.
如果二级索引被标记为缺失或者二级索引页被一个新事务更新了,索引覆盖技术不会使用.代替从索引结构中返回值,InnoDB会从聚合索引中查找记录.
然而,如果启用了索引条件下推(ICP)优化并且where条件中的部分可以只用索引字段计算的话,MySQL服务器仍然会下推这一部分的where条件到使用索引计算的存储引擎中去.如果没有找到匹配的记录则聚合索引的查找会被避免.如果找到匹配的记录,即使是被标记删除的记录,InnoDB也会到聚合索引中查找记录.