mysql删除了数据,为什么磁盘空间未释放?
问题由来
公司数据库,每天会自动全量备份数据库,由于数据量太大导致服务器磁盘空间增长极快。交付删除了大量无用数据后,发现数据库磁盘占用并未减小,于是有了这个问题。排查发现,确实数据已经被删除了,磁盘空间却并未释放,针对这个奇怪的现象。
那么我们来做一个测试, 创建一张MyTest表,通过测试数据生成器,插入10000条数据,发现已经占用了1552KB的空间
我们来执行下删除操作,将这1W数据全部删除
DELETE from mytest where 1=1;
执行完毕发现还是占用了,占用空间并未发生变化。
原因
MySQL在执行delete或者update操作时,有可能产生碎片。
在执行delete操作的时候,存储中会产生由于delete操作而留下的空白空间,而当有新数据插入时,MySQL会尝试使用这些空白空间,但是数据又不可能完全一致,正好把空白覆盖满,于是会就有空白空间出现。尤其是在大量delete操作的时候,会出现大量的空白空间。
在执行update的时候,例如在可变长度的字段,比如说varchar或lob,更新的数据可能和原来的长度不一样,这样也会产生碎片。比如说原始长度是varchar(100),但我们更新了大量长度为50的数据,这样的话,就有50的空间成为了空白。对于MySQL的innodb存储引擎来说,表存储数据的单位是页,而update操作会造成页分裂,分裂以后存储变得不连续、不规则,从而产生碎片。所以在使用mysql过程中,删除大量数据后,应该及时清理数据碎片,优化数据库性能。
后来读《mysql必知必会》,书中也提到了这么一句话
如果从一个表中删除大量数据,应该使用optimize table来收回所用的空间,从而优化表的性能。
# 结论
在大量删除表数据后,可能会造成数据空洞,可以使用以下方法来收缩表空间
1、使用optimize table来收回所用的空间,需要注意的是,optimize操作会锁表,所以不要在业务高峰期使用此操作
2、使用 truntace table 操作,此操作相当于先删除表结构,再重建了表结构,在操作前需要备份数据
3、alter table 表名 engine=InnoDB,通过重建表的存储引擎来重组数据和索引的存储,从而达到清理碎片的目的,这种方法需要扫描表数据文件,对于大表来说非常耗时,也需要避开业务高峰期