InnoDB怎么执行删除的?

InnoDB表都包含哪些部分

一个InnoDB表包含两部分,表结构定义和数据。
在MySQL8.0之前,表结构存在以.frm为后缀的文件里,MySQL8.0版本,已经允许把表结构定义存放在系统数据表中了(因为表结构定义占用的空间很小

简单的删除表数据,表占用空间不会减小

表数据既可以存在共享表空间里,也可以是单独的文件,这个行为是由参数innodb_file_per_table控制的:

  • 设置为OFF:表的数据放在系统共享表空间,也就是根数据字典放在一起
  • 设置为ON:每个InnoDB表数据存储在一个.ibd为后缀的文件中

从5.6.6版本开始,默认值就为ON了。

建议设置为ON,因为一个表单独存储为一个文件更容易管理,而且不需要这个表的时候,通过drop table命令,系统就会直接删除这个文件,而如果是放在共享表空间中,即使表删除了,空间也是不会回收的。

数据的删除流程

我们知道InnoDB是以B+数来存储数据的,假设主键索引树上的数据如下
InnoDB怎么执行删除的?

假如我们要删掉R4这个记录,InnoDB引擎只会把R4这个记录标记为删除(但是磁盘文件的大小并不会缩小),如果之后要再插入一个ID在300和600之间的记录时,可能会复用这个位置。

假如删除了整个数据页的数据,那整个数据页就可以被复用了。

数据页的复用和记录的复用的不同

记录的复用,只限于符合范围条件的数据;数据页的复用可以复用任何位置,任何新数据需要数据页都可以复用这个数据页。

数据页合并

如果相邻的两个数据页的利用率都很小,系统就会把这两个页上的数据合到其中一个页上,另外一个数据页就被标记为可复用。

delete 整个表?

使用delete命令把整个表的数据删除,所有的数据页都会被标记为可复用,但是磁盘上的文件不会变小。

数据空洞

这些可以被复用,而没有被使用的空间,看起来就像是“空洞”

插入数据造成数据空洞

  • 如果数据是按照索引递增顺序插入的,那么索引是紧凑的,不会造成数据空洞
  • 如果数据是随机插入的,就可能会造成数据页分裂,比如PageA已经满了,再要往PageA插入一条记录时,就不得不再申请一个新的PageB来保存数据了,这时就会产生页分裂,如果页分裂是从PageA的中间分裂的,页分裂完成后,PageA就会产生一半的数据空洞。

更新造成数据空洞

更新索引上的值,可以理解为删除一个旧的值,再插入一个新的值,和插入一样,这也会造成空洞


删除数据空洞

如果要我们做,我们可以新建一张与表A结构相同的表B,然后按照主键ID递增的顺序,把数据一行一行地从表A里读出来再插入到表B中,这样由于表B是新建的表,所以表A主键索引上的空洞,在表B中就都不存在了,使用表B替换A,从效果上看,就起到了收缩表A空间的作用。

MySQL的重建表

使用alter table A engine=InnoDB命令来重建表,在MySQL5.5版本之前,这个命令的执行流程和上边我们说的流程差不多,区别只是这个临时表B不需要我们创建,MySQL会自动完成转存数据,交换表名,删除旧表的操作。

缺点

耗时: 花时间最多的步骤是往临时表插入数据的过程
阻塞写: 如果在这个过程中有新数据要写入到表A的话,就会造成数据丢失,因此在整个DDL过程中,表A不能有些操作,也就是说这个DDL不是Online的

优化

MySQL5.6版本开始引入了Online DDL,对上边的操作流程做了优化。流程如下:

  1. 建立一个临时文件,扫描表A主键的所有数据页
  2. 用数据页中标A的记录生成B+树,存储到临时文件中
  3. 生成临时文件的过程中,将对A的操作记录在一个日志文件(row log)中,对应的是图中state2的状态
  4. 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表A相同的数据文件,对应的就是图中state3的状态
  5. 用临时文件替换表A的数据文件


通过日志文件记录+重放操作,就可以在拷贝数据的过程中仍然接收DML操作,达到近Online的重建表,为什么说是近Online呢,因为Alter命令在启动的时候要获取MDL写锁,但是这个写锁在拷贝数据之前就已经退化为MDL读锁了。

为什么要退化为MDL读锁?
MDL读锁不影响DML操作
为什么不直接解锁?
MDL读锁能防止其他线程对这个表的DDL操作

工具

GitHub 开源的 gh-ost

optimize table、analyze table 和 alter table 这三种方式重建表的区别

  • 从MySQL5.6版本开始,alter table t engine=InnoDB(也就是recreate)默认的就是上边的优化过后的流程了
  • analyze table t并不是重建表,只是对表的索引信息做重新统计,并没有修改数据,这个过程中加了MDL读锁
  • optimize table t等于recreate + analyze。
上一篇:阿里内部资料,10W字总结JAVA面试题-Mysql篇


下一篇:InnoDB存储引擎的索引与算法