mysql undo log研究

undo默认存放在 ibdata1中,即系统表空间中。

表空间内部由多个segment段对象(逻辑概念)组成,每个段由extend区(逻辑概念)组成,每个区由页(物理概念)组成,在每个页中保存数据。

rollback segment (回滚段)

1. MySQL 5.5前只有1个rollback segment

2. MySQL 5.5+ 有128个rollback segment

3. 不保存任何undo log

4. 仅保存undo log segment的位置

5. 含有1024个undo slot

mysql undo log研究

MySQL5.5中只有一个Rollback Segment,即只有1024个undo log segment,那就表示最多只有能有1024个并发事务(线程)去执行undo。

如果用不到undo,其实是可以超过1024个线程的。哪些线程会用到undo呢?增删改会用到,在秒杀场景下如果只有1024个undo log segment是不是会有问题的?

在MySQL5.6中支持128 * 1024 个并发执行undo的线程

undo log segment(undo日志段)

实际存储undo log的对象

由undo page组成

每个undo page可以保存多个事务的undo log

 

最重要的是undo log中存储了哪些内容

undo log header

undo log records

undo log记录分为两种, insert 的undo和update 的undo

 

1. insert undo log record – 记录insert

2. update undo log record – 记录update和delete

undo 是逻辑记录,记录了每一行修改的值(前后项)。

mysql undo log研究

purge

真正的删除记录

删除undo log

 

举例:表tb1 中有记录pk=1,2,3;此时delete from tb1 where pk=1;

1. 将pk=1的记录标记为删除(delete-mark,info bits),数据库中pk=1的记录此时还是存在的,空间并没有被释放,该操作为同步操作(SQL执行完,也就标记完成了)。

2. purge,该部分为后台线程(purge线程)异步操作,会真正的删除该记录,且空间被释放。purge线程是系统自动的,无法人工控制。

 

标记为已删除的原因:

1. 该事务可能需要回滚,先作保留。

2. 当事务1去删除pk=1且没有提交时,事务2应该要能看到pk=1的记录(事务的隔离性)。

 

我们既然有了undo日志,为什么还要delete-mark,然后purge呢?

在这里,我们要区分几种情况了

 

当过滤条件是聚集索引时:

delete – 将该记录标记为delete-mark 。

update – 将该记录先物理delete(聚簇索引里主键相同的行最多只能有1个),然后insert或者可以原地更新[in place update](即使删除了,也可以通过undo进行还原)。

 

当过滤条件是二级索引时

1. delete – 将该记录标记为delete-mark 。

2. update – 将该记录标记为delete-mark (索引列是columns + pk,即使是唯一索引更新也是和原来的不一样),然后insert。

 

为什么insert不需要purge?

1.insert操作是不需要异步去purge,因为insert的记录之前是不存在的

2.不存在记录(未提交)是没有别的事务能引用到的,所以insert以后,对应的undo可以直接删除,而不需要等待异步purge