文章目录
- 1.主键优化方面的概念
- 1.1.数据的组织方式
- 1.2.主键顺序写入的过程
- 1.3.主键乱序写入引发页分裂的现象
- 1.4.页合并的概念
- 2.主键的设计原则
1.主键优化方面的概念
1.1.数据的组织方式
在InnoDB存储引擎中,表的数据都是根据主键顺序组织然后存放的,这种存储方式的表也叫做索引组织表(index organized table IOT)。
在聚集索引中,非叶子节点仅仅起到一个索引数据的作用,叶子节点下挂的都是一行数据,每个叶子节点中主键索引元素都是有顺序关联在一起。
无论是叶子节点还是非叶子节点,数据都是存放在页这个逻辑结构中的,一个页的大小为16K,这也意味着一个页中存储的行是有限的,如果插入的数据在这个页中存储不下,此时会存储在下一个页中,页与页之间通过指针连接。
1.2.主键顺序写入的过程
每一行数据都是存储在页中的,一个页可以是空的,也可以只写入一半的数据,也可以写满整个页,但是每个页中至少要包含2行数据,页中的每条数据都是根据主键进行排列顺序写入。
如果一个页中只有一行数据,页与页之间再进行指针连接,就成了二叉树链表的概念.
我们通过下面这幅图观察主键顺序写入的过程:
- 首先在磁盘中申请一个页page(1),按照主键值的顺序将写入到第一个页中。
- 当发现第一个页还能写入数据时,数据依旧会在第一个页中写入。
- 当第一个页写满数据后,会在申请一个页page(2),接下来的数据就会写入到第二个页中,页与页之间会通过指针进行连接。
- 每当一个页无法再写入数据时,就会再申请一个新的页,继续写入数据。
按照主键顺序在页中写入数据时没有任何问题的,性能也是最高的。
下面我们再来看主键乱序写入会引发的问题。
1.3.主键乱序写入引发页分裂的现象
当我们表中主键字段是乱序写入的情况,就会引发页分裂的现象。
**页分裂的概念:**由于表中主键的数据都是乱序写入,而页中的主键都是顺序存放的,在一个页中存放了一组乱序写入的主键数据,此时又有新的主键要存放到页中,但是页已经满了,页里面的数据都是顺序存放,恰好新增的这个主键就应该存放在这个页里,这时就会产生页分裂的现象,将这个页拿出50%的数据放到一个新的页中,然后将主键数据写入到页中,最后重新分配指针。
下面通过几幅图来演示页分裂的过程:
1)当前有两个页,page1和page2,这里面的主键都是乱序写入的,但是按照页的特性还是将乱序的主键按照顺序排序。
2)此时表中新增了主键为50的一条数据,我们来分析它会不会写入到新的页page3中呢?
其实是不会的,因为页中叶子节点是有顺序排序的,50在47和55之间,应该写入到第一个页或者第二个页中,但是这两个页此时都满了,无法再写入数据了,那么又应该怎么办呢?
3)50在47和55之间,但是第一个页和第二页都满了,无法写入50的数据,此时会申请一个新的页page3。
4)但是并不会直接将50存入page3这个页中,因为这样一来叶子节点就不是顺序排序的了,而是会将第一个页中一半的数据移动到page3这个页中,然后在47的后面插入50这个主键。
5)虽然数据已经写入到新的页中了,但是此时还没有结束,因为这时候叶子节点还不是顺序排序的,按照顺序排序,第三个页此时就应该放在第一个页和第二个页的中间,然后重新设置链表指针,完成数据的关联。
这就是整个页分裂的完整流程,新主键按照顺序写入到该写入的页,但是由于数据满了无法写入,此时就会将这个页中一半的数据拿到新的页中然后将新主键也写在这个新页中,然后移动这个新页到顺序页的位置,最后重新分配指针。
页分裂是比较耗费性能的
1.4.页合并的概念
页合并指的是将有合并可能的多个页组合成一个页,减少索引的空间。
当我们要删除一行记录时,实际上记录并没有被物理删除,会将记录标记为删除的状态,此时这个记录占用的页空间就会允许被其他的数据所使用。
当页中删除的数据达到整个页空间的50%时,也就是说当页的空间空余有50%时,InnoDB就会寻找靠近这个页前后的其他页,分析是否可以将其他的页与这个页合并在一起,从而优化空间的使用。
我们通过下面几幅图来演示页合并的过程:
1)我们要将第二个页中50%的数据删除,后半部分的数据都会标记为删除的状态,此时这些数据占用的空间可以理解为被释放了,允许新的数据写入。
2)当页的剩余空间达到50%时,InnoDB就会寻找靠近第二个页前后的其他页,分析是否有合并的可能性。
3)根据分析发现第一个页是满的,没有合并的条件,而第三个页有恰好有50%的数据可以与第二个页合并,合并后就可以释放第三个页,用来优化占用的空间。
4)页合并之后,新来的主键数据发现第二个页现在是满的,就会在第三个页中写入数据。
这就是完整的页合并现象,当达到页的空间阈值时,就会触发页合并操作,优化占用的空间。
具体页的空间剩余多少时,触发页合并可以通过
MERGE_THRESHOLD
参数来设置,默认是50%,在创建表或者索引时指定。
2.主键的设计原则
- 满足业务需求的情况下,尽量降低主键的长度,长度太长会消耗检索的性能。
- 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键的方式,避免页分裂。
- 尽量不要使用UUID或者身份证作为主键,一来是长度很长,二来都是随机顺序,乱序写入,会引发页分裂。
- 业务操作时,避免对主键进行修改。