[翻译] MySQL 之 InnoDB 中的 Multi-Ver
2020-03-15 本文已影响0人
猿来是八阿哥
mysql
一、多版本存储引擎 ---
1. 回滚片段 ---
2.
3. 回滚日志
二、
2. 二级索引
一、多版本存储引擎 --- 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
中的记录。
- 如果存储引擎没有拿到结果,从聚簇索引
-