在整理undo log笔记前我感受它应该是在 undo、redo、bin log三者中须要整理的内容最少的。可是实际上并非想象的那么简单。html
关于undo log须要整理的两大块知识点分别是:mysql
一、简介undo log、truncate、以及undo log如何帮你回滚事物(本篇分享) sql
二、undolog链条、ReadView、以及undo log如何帮你实现MVCC多版本并发控制(明天分享)
数据库
若是你看了白日梦前面的分享的笔记,你确定知道了什么表空间。其实所谓的表空间实际上是真实存在于磁盘上的数据文件。而这里的所说的undolog表空间其实就是磁盘上专门存放undo log的文件。bash
表空间由不少 segment(段) 组成,而这众多的段中有一种就是 undo segment。并发
默认状况下undo segment 会存放于系统表空间中,或者说undo log默认会记录在共享表空间文件中(文件真实存在)。测试
可是MySQL也提供了参数,让你能够控制MySQL讲undo log写入到单独的表空间文件中去。尤为是当你使用SSD这种存储时,尤其推荐将undo log从共享表空间中拿出去。spa
默认状况下undo log tablespace个数是0,也就是说若是你不干涉MySQL的配置。那么MySQL就会帮你将undo log记录到共享表空间中。线程
MySQL默认的配置文件 my.cnf 长下面这样:设计
若是你如今仅仅是安装了MySQL,而未曾启动过mysql,那你去datadir中查看会发现它只是个空目录。
可是当你启动过MySQL以后,再去这个datadir中查看会发现里面多了不少文件,其中就包括共享表空间文件ibdata1(可是没有undolog表空间文件)。以下:
若是你想将undo log拿到undo log表空间文件中。那你能够像下面这样修改MySQL的配置文件my.cnf
修改完后经过以下命令启动mysql
systemctl start mysqld.service
可是你会发现启动不了,若是你去排查缘由就会发现:由于曾经初始化过 datadir 目录中的文件,你添加的新配置innodb_undo_tablespaces和原来的配置是冲突的,须要开辟新的表空间文件,因此致使启动失败。
解决的方式:简单粗暴的将换个datadir文件就好啦,因此若是你从一开始就想将undolog拿到单独的表空间中,那么最好从一开始就将这个配置添加进去,不然仍是挺麻烦的。
本文是第14篇,全文近100篇,点击查看目录
提到了undo log,就不得不说roll back segment这个知识点了。它并不难理解,你能够阅读下面的介绍了解一下。
InnoDB存储引擎会先初始化好rollback segment(回滚段),在每一个回滚段中会记录N个undo log segment,而咱们说的undo log就是在 undo log segment中申请出来的!
在早期的InnoDB版本中只有一个rollback segment,所以在同一时刻它支持的在线事物的上限被限制在1024个。
在MySQL5.7中回滚段已经支持到了128个(上限是128)。其中32个分配给临时表空间。剩下的96个回滚段能够分配给修改常规表中数据的事务。
用户能够经过参数innodb_rollback_segments
调整回滚段的数量。
另外,咱们上面提到的: 每一个回滚段中都记录了N个undolog segment, 这里的N和数据页大小有关
InnoDB页面大小 | 回滚段中的撤消插槽数(InnoDB页面大小/ 16) |
---|---|
4096 (4KB) | 256 |
8192 (8KB) | 512 |
16384 (16KB) | 1024 |
32768 (32KB) | 204 |
65536 (64KB) | 4096 |
truncate意为:截断
其实结合 truncate table sql,就能更好的理解这个概念。当你不须要某个表中的数据时,你能够执行truncate sql将表中的数据清空掉。一样的undo log的truncate机制本质上就是为undo log 表空间文件瘦身,将不须要的undo log清理掉。
在MySQL 5.6(包括5.6)以前Undo tablespace里面的undo数据文件是没法收缩的。也就是说在实例的运行过程当中若是遇到有大的事务,会把undo log的文件撑的很是大。浪费大量的空间甚至会把磁盘打爆。同时也增长了数据库物理备份的时间。
在MySQL5.7中容许用户在线truncate undo log
前提:必须使用独立的undo表空间
而后配合以下的参数辅助:
建立数据表:
create table test ( id int primary key auto_increment, name varchar(64) );
而后不断的往这个测试表中插入数据
insert into test(name) values(repeat('a',64)); insert into test(name) select name from test;
一边插入一边观察undo 表空间文件的变化:你会发现undo003这个表空间文件已经超过了参数:innodb_max_undo_log_size=100M
指定的范围,意味着这个undolog已经被标记为可回收了。
当事物提交时,undo log并不会被当即删除,由于可能存在其它的事物须要使用undo log将数据回滚到以前的版本。最终是否能够删除undo log由purge线程决定。
为了让pruge线程运行,能够执行以下的sql
delete from test limit 1;
undo log有两种类型,分别是 insert undo log 和 update undo log。
前者记录的是insert 语句对应的undo log。
后者对应的是 update、delete 语句对应的undo log。
对于 insert 类型的sql,会在undo log中记录下方才你insert 进来的数据的ID,根据ID完成精准的删除。
insert 类型的undo log长下面这样:
可能你打眼一看上图就能知道各部分都有啥用。
可是,不知道你会不会纳闷这样一个问题:不是说对于insert 类型的undo log MySQL记录的是方才插入行ID吗?怎么上图整出来的了这么多Col一、Col二、Col2。
实际上是MySQL设计的很周到,由于它是针对联合主键设计的。
一条update sql对应undolog长以下这样。
其实我感受不必记住这个图,记住了也会忘。大概看一下它长什么样子就好。
重点是下面会分享的,undo log链条,而且你得知道这个链条能够帮你实现事务的回滚
举个例子:
对于 insert 类型的sql,会在undo log中记录下方才你insert 进来的数据的ID,当你想roll back时,根据ID完成精准的删除。
对于delete类型的sql,会在undo log中记录方才你删除的数据,当你回滚时会将删除前的数据insert 进去。
对于update类型的sql,会在undo log中记录下修改前的数据,回滚时只须要反向update便可。
对于select类型的sql,别费心了,select不须要回滚。
先看一个简单的insert undo log 链条
有一个注意点:由于单纯的insert sql不涉及多MVCC的能力。
因此一旦事务commit,这条insert undo log就能够直接删除了。
再看一个update类型的undo log
为了方便画图,重点突出链条的概念我省略了update undo log的部份内容
一个事物A开启后插图了一条记录:name = tom,MySQL会记录下这样一条undo log
随后前后来了两个事物:
事物B,事物ID=61,它执行sql将name 改为jerry。
事物C,事物ID=62,它执行sql将name 改为tom。
因而MySQL记录下这样一条新的undo log
你能够看到,MySQL会将对一行数据的修改undo log经过DATA_ROLL_ID指针链接在一块儿造成一个undo log链表链条。这样事物C若是想回滚,他会将数据回滚到事物B修改后的状态。而事物B想回滚他会将数据回滚到事物A的状态。
在前面的文章中有专门的介绍:表空间、数据表、数据区、数据页。
表空间、数据页存在于物理层面。SQL想要修改的数据表、id=xxx的行都是逻辑上的。
而 undo log 帮你作的是逻辑上的数据回滚,而不是物理(数据页)上是数据回滚。
其实在逻辑层和物理层都能回滚。
那,你有没有想过为何undo回滚的层面要设置在逻辑层而不是物理层的数据页级别?
缘由你能够这样想:假如一个数据页中存了300行数据,而你的update语句其实可能仅仅是更新了这个数据页中的一行。可是数据库可不必定是你本身在用!极可能有其余的用户也在使用而且修改了该数据页中的另外200行。那这时若是你基于数据页层面回滚,岂不是会将别人的不想回滚的数据给改错?
在MySQL5.六、MySQL5.7版本中能够经过innodb_undo_tablespaces
参数配置redo log表空间文件的个数,可是官网也有介绍这个参数在将来的MySQL版本中将会被废弃,在MySQL8.0中初始化MySQL实例时会建立两个默认的撤消表空间,而且可使用CREATE UNDO TABLESPACE
语法建立其余撤消表空间 。
可是无论怎么样,若是你使用的是MySQL5.7仍是推荐使用这些参数以及开启undo log的自动truncate。
参考:
《MySQL技术内幕》
https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-logs.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-tablespaces.html
https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_undo_tablespace
本文是第14篇,全文近100篇,点击查看目录