MySQL45讲之表空间回收

前言

本文介绍为什么删除了一部分表数据后,表文件大小不变,以及有哪些表空间回收的方式。

为什么删除表数据后,表文件大小不变

MySQL 采用的是标记删除,需要等待后台 purge 线程删除数据。但是,purge 线程删除数据后,表空间依然不会回收。

对于一个数据页,删除了其中若干行数据,因为还有其他数据,数据页不会回收,并且,空出来的位置会复用。即使一个数据页数据都被清空,这个数据页也不会被回收,而是也用于复用,当需要新创建数据页时,会直接使用这个可复用的数据页。

那应该怎么回收表空间呢?答案是重建表。

表空间回收方式

重建表推荐使用 ALTER TABLE t ENGINE = InnoDB; 。在不同的 MySQL 版本中,这条语句的执行方式不同。

Copy Table

MySQL5.5 之前采用 Copy Table 方式重建表,Alter 期间,只支持 DML 查询操作,不支持 DML 更新操作,语句为 alter table t engine=innodb, ALGORITHM=copy;

1、server 层创建与原表结构相同的临时表
2、根据主键递增顺序,将一行一行的数据读出并写入到临时表,直至全部写入完成
3、互换原表和临时表表名
4、删除临时表

Online DDL

MySQL5.6 开始采用 Inplace 方式重建表,Alter 期间,支持 DML 查询和更新操作,语句为 alter table t engine=innodb, ALGORITHM=inplace;。之所以支持 DML 更新操作,是因为数据拷贝期间会将 DML 更新操作记录到 Row log 中。

重建过程中最耗时的就是拷贝数据的过程,这个过程中支持 DML 查询和更新操作,对于整个 DDL 来说,锁时间很短,就可以近似认为是 Online DDL。

1、获取 MDL(Meta Data Lock)写锁,innodb 内部创建与原表结构相同的临时文件
2、拷贝数据之前,MDL 写锁退化成 MDL 读锁,支持 DML 更新操作
3、根据主键递增顺序,将一行一行的数据读出并写入到临时文件,直至全部写入完成。并且,会将拷贝期间的 DML 更新操作记录到 Row log 中
4、上锁,再将 Row log 中的数据应用到临时文件
5、互换原表和临时表表名
6、删除临时表

注意,两种拷贝方式都需要额外的一份存储空间,所以,在存储空间不足的情况下,重建表会失败。

对于大表的重建,十分消耗 IO 和 CPU 资源。如果是线上服务,为了安全性考虑,建议使用 GitHub 开源的 gh-ost 来做。

Online和Inplace

Inplace 替换,表示在 InnoDB 内部完成了重建过程,不是在 server 层。

Online 采用的就是 Inplace 的重建方式。但是,Inplace 方式并不一定是 Online,比如添加全文索引时 alter table t add FULLTEXT(field_name); 就不是 Online 的,因为它会阻塞 DML 更新操作;而 Online DDL 一定是 Inlpace 方式的。

alter table、analyze table和optimize table解释

alter table t engine = innode;(也就是 recreate)就是 Online DDL 重建表过程;

analyze table t; 不是重建表过程,它只是对索引信息重新统计,会上 MDL 读锁;

optimize table t;是 recreate + analyze 过程。

参考

上一篇:MySQL45讲之order工作原理


下一篇:MySQL45讲之优化器选错索引