
mysql
一、多版本存储引擎 --- InnoDB
InnoDB 是一个多版本存储引擎 multi-versioned storage engine,它保存了 修改行的新、老两个版本 的数据信息,以支持事务的并发和回滚。
1. 回滚片段 --- rollback segment
InnoDB 在表空间中,用一个叫 回滚片段 (rollback segment) 的数据结构,保存了行的新、老两个版本 的数据信息。实现了:
-
InnoDB可以使用这个回滚片段 (rollback segment)来执行事务的回滚。 -
InnoDB可以使用这个回滚片段 (rollback segment)为一致性读consistent read(也称为当前度current read),构建行数据的早期版本。
2. multi-version 的具体实现方式
在内部,InnoDB 为每行数据增加了三个字段:
-
DB_TRX_ID,6-byte:-
DB_TRX_ID存储了:插入或修改这条数据的最后一个事务的 ID。 - 由于在
InnoDB内部,删除被看做是一种特殊的更新,DB_TRX_ID中有一个特殊位标识了是否是删除状态。
-
-
DB_ROLL_PTR,7-byte:-
DB_ROLL_PTR是一个回退指针roll pointer,指向了:由rollback 语句写入undo log中的一条记录record。 - 当行数据被更新时,这条
undo log中的记录record,包含了:将行数据恢复到行数据更新前的数据的全部信息。
-
-
DB_ROW_ID,6-byte:-
DB_ROW_ID保存了:每行数据插入时生成的自增ID - 如果这个
InnoDB的表中包含了一个聚簇索引clustered index(包含了一个主键列),DB_ROW_ID中存储的行自增ID,也会保存到这个聚簇索引clustered index中。 - 如果这个
InnoDB的表中没有包含了一个聚簇索引clustered index(没有主键列),DB_ROW_ID中存储的行自增ID不会出现在任何索引中。
-
3. 回滚日志 undo log 的生命周期及一些建议
- 回滚日志
undo log分为:- 为了插入数据的回滚日志
insert undo log - 为了更新数据的回滚日志
update undo log
- 为了插入数据的回滚日志
- 插入数据的回滚日志,为了支持
事务回滚功能(当要删除数据的事务回滚时),且当事务提交时会马上删除。 - 更新数据的回滚日志,为了支持一致性读
consistent read(也称为当前度current read),且当没有任何事务在使用「更新回滚日志」来构建行数据的早期版本,以支持「一致性读 consistent read(也称为当前度 current read)」时会马上删除。 - 定时提交你的事务,即使是那些只包含了一些一致性读
consistent read(也称为当前度current read)的事务。否则,海量的更新数据的回滚日志无法删除,将沾满你的表空间。 - 回滚日志
undo log的实际物理大小一般会小于插入或更新的行,因此你可以大概计算出,事务所产生的用户事务回滚的回滚日志的大小。 - 在多版本的
InnoDB表中,当你使用delete语句删除某些行时,这些行并不会马上进行物理删除,而是要等到InnoDB删除了那条delete语句所对应的回滚日志时,才会对行数据和对应的索引数据进行物理删除。这个过程叫做purge,它和执行delete语句时一样快。 - 如果你按照一定的速度,一批一批的删除或新增数据,上述的
purge工作会持续地滞后,造成需要物理删除的数据越来越多,使得表空间越来越大,磁盘的purge工作将使得一切都很慢。可以通过修改innodb_max_purge_lag配置项,强制InnoDB减速,以保证purge能跟得上。
二、 multi-version 与二级索引 secondary indexes
1. 区别
InnoDB 的多版本并发控制 MVCC - Multi-Version Concurrency Controll 对于聚簇索引 clustered index 和二级索引 secondary indexes 将会区别对待:
- 聚簇索引
clustered index中的记录会马上更新,对应地,这些记录指向早期版本回滚日志的隐藏字段(DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID)也会马上重建。 - 而二级索引
secondary indexes中不包含隐藏字段(DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID),也不会马上更新。
2. 二级索引 secondary indexes 的更新
- 当二级索引
secondary indexes的列被更新时,老的二级索引记录会做删除标识,然后会插入新行,最后二级索引中记录的删除标识会被删除。 - 如果二级索引
secondary indexes的记录被做删除标识或者一个更新的事务对二级索引页secondary indexes page进行更新时:-
InnoDB会查找表的聚簇索引clustered index中的记录:在聚簇索引clustered index中,检查记录的DB_TRX_ID,如果记录在只读事务开始后被修改了,InnoDB会根据回滚日志将正确的记录构造出来retrieved。 - 同时索引覆盖
covering index功能不再支持:InnoDB会从聚簇索引clustered index中查找记录,而不是直接使用索引中的数据。 - 不过,如果开启了
index condition pushdown (ICP)(MySQL 用索引去表里取数据的一种)优化,并且部分where条件可以从索引中的字段进行评估,MySQL 依然会将这些使用索引中字段评估过的部分 where 条件下发到存储引擎。此时:- 如果存储引擎没有拿到结果,从聚簇索引
clustered index中查找记录的过程会被省略。 - 如果存储引擎找到了结果,甚至包含了已经在二级索引
secondary indexes中被做删除标识的记录,InnoDB会查找表的聚簇索引clustered index中的记录。
- 如果存储引擎没有拿到结果,从聚簇索引
-