数据删除流程

假如现在有如下数据:

image-20230406143630354

假如此时我们要删除R4的数据,InnoDB引擎只会把R4这个记录标记为删除。如果之后需要再300和600之间插入数据,可能会复用这个位置。所以这时删除一条数据时空间不会变小。

如果我们删除一整个页的数据,那么这整个数据页都可以复用。

如果删除了一整张表,那么所有的数据页都会被标记为可用。

以上这三个删除都是针对delete命令。

也就是说,delete命令只会把对应的数据标记为可以复用,下次需要写对应位置的数据时,直接覆盖掉原来的数据,并没有真正的释放空间。如果这些位置没有被复用,就会造成空间的浪费。

不仅删除会导致这些空洞,插入数据也会。因为如果插入的数据不是按照索引有序的,就有可能导致页分裂。比如数据页A已经存满了,此时又有一条数据需要插入数据页A,此时会导致B+树页分裂,会多出一个数据页,但是数据页A和新数据页都不会存满数据。

重建表

如果想要消除表里面的空洞,就需要重建表。即把数据按照有序的方式从表A插入到表B当中,然后利用表B替换掉表A。在这个过程中,表A不能有更新操作。

Online DDL

在MySQL 5.6之前,重建表的逻辑和上面说的类似,但是5.6之后对此做了优化,大致过程如下:

先生成一个临时文件,然后遍历表A的数据,生成一颗B+树(这里生成的B+树就是顺序生成的),然后用一个日志(row log)记录在扫描A时一些其他操作对表A的修改。然后先将生成的B+树存入临时文件,再把日志操作用于临时文件,之后用临时文件替换表A。

参考

《MySQL45讲》