上篇文章我们讲到了 MySQL 的数据页,我们说到了 InnoDB 的索引是以 B+树的形式构建的,而且 B+树的节点都是一个数据页。
但是 B+树在使用过程中难免会有节点分裂和节点合并的过程。
因为我们是以数据页为基本单位构造的 B+树,那么 B+树的节点分裂和节点合并就会造成数据页的页分裂和页合并。
我们都是知道,B+树是按照索引字段建立的,并且在 B+树中是有序的,假如有下面一个索引的树结构,其中的索引字段的值并不连续。
1、页分裂
假如,现在我们插入一个新的一条记录,他的索引值是 3,那么他就要按照顺序插入到页 20 中,在索引值为 1,2 的记录的后面。而如果这个索引页已经满了,那么就需要触发一次页分裂。
页分裂是指将该页面中的一部分索引记录移动到一个新的页面中,从而为新记录腾出空间。这样可以保持 B+树的平衡和性能。
以下,就是一次页分裂的过程:
当我们插入一组无序的数据的时候,那么就可能导致多次的页分裂的情况。
而且某些情况下,可能会从叶子节点一路分裂到根节点(B+树的非叶子节点也存储数据,也可能分裂)。
2、页合并
既然会有页分裂那么就会有页合并。
页分裂发生在 insert 阶段,那么页合并就是发生在 delete 阶段。
当我们删除索引下的数据的时候,叶子节点的数据就会变得比较稀疏,此时 B+树就会触发合并操作。
3、页分裂和页合并的影响
首先,页分裂和合并是涉及大量数据移动和重组的操作。频繁进行这些操作会增加数据库的/O 负担和 CPU 消耗,影响数据库的整体性能。
第二,分裂和合并可能导致 B+树索引结构频繁调整,这个过程也会影响插入及删除操作的性能。
第三,频繁的页分裂和合并可能会导致磁盘上存在较多的空间碎片,新分出的一个页一般会有很多空闲空间,使得数据库表占用更多的磁盘空间,而导致浪费。
因为一个数据页是 16KB,如果此时的叶子节点存储两条数据也是需要 16KB,剩余的位置填充对齐。存储五条数据的时候也是 16KB。所以空间碎片会导致磁盘空间的浪费。
4、避免页分裂
1、我们在设置主键的时候尽量选择能够自增的字段
2、不要使用 varchar 类型作为 ID 主键。
3、我们在生成全局唯一 ID 的时候尽量不要使用 UUID,UUID 不是自增的。