> 文档中心 > MySQL表空间碎片

MySQL表空间碎片


一、起因

在测试环境清空了某一个数据量较大的MySQL 表,但发现,其仍占据着存储空间

心生疑问,故搜索了一番,在此简单做个整理。

二、出现碎片的原因

  • 在InnoDB 中,删除一些行,这些行只是被标记为“已删除”,而不是真的从索引中物理删除了,因而空间也没有真的被释放回收,这些可以称为是空白空间
  • 当执行插入操作时,MySQL 会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用,仍然无法将其彻底占用,就形成了碎片
  • 频繁修改了含有可变长度列的表(如:含有VARCHAR、BLOB 或TEXT 列的表),改短一些的时候就会出现非常小的空白空间,改长的话就有可能会因为空间不足导致把数据行的一些数据迁移到其他地方去

举个例子,假设一条记录二十个字节。
将两万条记录删到只剩一行,列表中有用的内容将只占二十字节。
如果没有及时插入,MySQL在 读取时会仍然将其视同于一个容量为四十万字节的列表进行处理,但实际上除了这二十字节以外,其它空间都被白白浪费了。

三、清理碎片的好处

当MySQL 对数据进行扫描时,它扫描的对象实际是表的容量需求上限,也就是表的数据实际占用空间 + 空白空间。

定期进行表空间整理,消除碎片可以

  1. 减少表数据与表索引的物理空间,降低磁盘空间使用率
  2. 降低访问表时的IO,提高MySQL 性能

举个例子,一个公司有10 个员工,10 个座位,被开除了7 个员工,但这些座位还是保留的。
碎片整理就像,让剩下的3个员工都靠边坐,然后把剩下的7 个座位给砸掉,这样就能释放出空间了。

四、检查表空间碎片

使用下面的命令检查数据库各数据表的空间使用情况:

show table status from db_name

查询结果如下:
MySQL表空间碎片
其中Date_free 代表的就是空白空间,即碎片。当Date_free 大于0 时就表示对于的数据表存在碎片。

五、清理碎片

5.1 OPTIMIZE TABLE table_name

使用下面的命令进行碎片的清理:

optimize table 表名
  1. 支持的表类型:INNODB、MYISAM、ARCHIVE、NDB。
  2. 会重组表数据和索引的物理页,对于减少所占空间和在访问表时优化IO有效果。
  3. 在OPTIMIZE TABLE 运行过程中,MySQL 会锁定表,数据量越大,耗费的时间也越长。
  4. 并不是所有表都需要进行碎片整理,一般只需要对包含可变长度的文本数据类型的表进行整理即可。
  5. MySQL 官方建议不要经常(每小时或每天)进行碎片整理,一般根据实际情况,只需要每周或者每月整理一次即可。
  6. 只适用于独立表空间。

独立表空间:就是采用和MyISAM 相同的方式,每个表拥有一个独立的数据文件( .idb )。

  1. 每个表都有自已独立的表空间。
  2. 每个表的数据和索引都会存在自已的表空间中。
  3. 可以实现单表在不同的数据库中移动(将一个库的表移动到另一个库里,可以正常使用)。
  4. drop table 自动回收表空间,删除大量数据后可以通过alter table XX engine = innodb; 回收空间

optimize table 的操作,在MySQL5.5 和5.6 中,实际上执行的过程是,首先创建一张新的临时表,把旧表锁住,禁止插入删除只允许读写,接着把数据不断从旧表拷贝到新临时表,拷贝完成后,进行瞬间rename 操作,再删除旧表。

5.2 ALTER TABLE table_name ENGINE= INNODB

使用下面的命令进行碎片的清理:

ALTER TABLE table_name ENGINE= INNODB
  1. 实际执行的是一个空的 ALTER 命令,但是这个命令也会起到优化的作用,它会重建整个表,删掉未使用的空白空间。
  2. 会重新整理在聚簇索引上的数据和索引。

5.3 是用OPTIMIZE TABLE 还是ALTER TABLE xxxx ENGINE= INNODB 好?

其实对于InnoDB 引擎,ALTER TABLE xxxx ENGINE= INNODB 是执行了一个空的ALTER TABLE操作。

而OPTIMIZE TABLE 等价于ALTER TABLE … FORCE。

在有些情况下,OPTIMIZE TABLE 还是ALTER TABLE xxxx ENGINE= INNODB 基本上是一样的。

但是在有些情况下,ALTER TABLE xxxx ENGINE= INNODB 更好。

例如old_alter_table 系统变量没有启用等等。

另外对于MyISAM 类型表,使用ALTER TABLE xxxx ENGINE= INNODB 是明显要优于OPTIMIZE TABLE 这种方法的。

5.4 使用Navicat 单独清理某个表空间碎片

选择具体的数据表,鼠标右击后选择【维护 -> 优化表】即可,其效果与OPTIMIZE TABLE 大抵相同。
MySQL表空间碎片
好了,本文到此结束。

我是陈冰安,Java 工程师,时不时也会整一整Linux 。
欢迎关注我的公众号【暗星涌动】,愿与你一同进步。

笑话娱乐网站