✅MySQL为什么会有存储碎片?有什么危害?

典型回答

MySQL中的数据库表会存在物理存储碎片,这种情况通常发生在频繁执行插入、删除和更新操作的数据库中。这些操作会导致表中的数据页部分空间未被有效利用或数据在物理存储上的排列不连续,从而形成碎片。

碎片的主要来源是因为存在频繁的 DML 操作,如 insert、update以及 delete,除此之外,还有如果我们使用 varchar 或者 text 这种可变长度字段存储的时候,更新时如果长度发生变化,也会存在碎片。

insert 导致的碎片

我们都知道,InnoDB 使用 B+树索引结构存储数据,并且数据通常按主键顺序存储。当我们的主键并不是顺序自增时,比如用UUID,那么新插入的数据行可能会导致页分裂现象。

页分裂会导致数据分散在磁盘上多个不同的位置。新创建的页可能在物理存储上与原始页相距甚远,呢么这些数据在物理上就不是连续的,那么就会存在碎片。

页分裂发生在向 B+树索引中插入新数据时,如果目标页已满,系统需要为新数据腾出空间。在这种情况下,数据库将执行页分裂操作

✅什么是InnoDB的页分裂和页合并

update 导致的碎片

前面说的 insert 导致碎片的情况,update 也同样会发生,除此之外,如果更新操作导致数据行大小增加,而原位置周围没有足够的空间容纳更新后的行,这行数据可能会被移动到数据文件的其他部分,这样就会留下空闲位置,导致碎片。

delete 导致的碎片

最容易导致碎片的,其实是 delete 操作,尤其是在 InnoDB中,delete执行后,只是给数据做了个标记,但空间并不会立即释放。这导致数据页中可能存在大量未使用的空间,增加了数据的分散程度,这就是碎片。

碎片的危害

当表的碎片增多时,数据在物理磁盘上的存储变得不连续,这将导致数据库在查询数据时需要更多的磁盘I/O操作,从而降低查询效率

碎片会导致数据库实际占用的存储空间比数据实际需要的空间大,这会大大的浪费磁盘空间,还可能影响缓存效率。

碎片化的数据会增加备份文件的大小,同时也会使得备份和恢复的过程变得更慢,因为备份和恢复操作也会受到物理读写速度的影响。

所以,我们应该尽可能的减少碎片的出现。

如何避免碎片

1、使用连续自增的 ID,而不是用 UUID,这样可以使新创建的对象在B+树的后面插入,可以减少页分裂。

2、对于固定长度的字符串,用 char 代替 varchar

3、避免在高度易变的列上创建索引,因为这会频繁触发页分裂。

4、使用OPTIMIZE TABLE命令可以重新组织表和索引的物理存储。这个命令可以有效减少碎片,优化表的存储和访问速度。

原文: https://www.yuque.com/hollis666/xkm7k3/dgehrxlnpsrdi83e