在前面的文章中我们可以聊了很多索引相关知识,具体内容详情可以参考
但随着深入学习我们知道索引并不只是B+树那么简单,而是一个复杂的结构,所以今天来聊聊索引的注意事项。
之前的文章画B+树索引为了推导方便每次都是先画叶子节点,然后一层一层的画目录项数据页,直到最后画根节点,也就是从下往上画,结构如下
那是不是说先有叶子节点,再有根节点呢?显然并不是,在InnoDB存储引擎中,是先有根节点再有叶子节点,具体操作过程如下
每当为一个表创建一个B+树索引的时候,就会创建一个根节点,最开始创建时数据表并没有数据,那么根节点为空。
当在表中插入一条用户数据,这时会先把用户数据插入到根节点中。
当根节点数据页可用空间不足,那么就会将根节点数据复制到一个新数据页暂且将其命名为a,然后将数据页a页分裂操作(因为新数据页不够存放根节点数据和新插入数据),得到另一个数据页b,根节点到这时才会升级为目录项数据页。
后续用户数据插入,就会根据索引类型得到排序值(聚簇索引为主键值,二级索引为指定列值),确定插入数据页a还是数据页b,完成插入。
根节点数据页从索引创建起就存在了,后续都不会改变,因为这个数据页的页号会被记录到某个地方,后续根据索引搜索都会用到这个页号,访问索引。
在之前文章索引分类中谈到二级索引就是给非主键列创建一个B+树,例如存在如下测试表
mysql> CREATE TABLE index_test(
-> c1 INT,
-> c2 INT,
-> c3 CHAR(1),
-> PRIMARY KEY(c1)
-> ) ROW_FORMAT = Compact;
Query OK, 0 rows affected (0.01 sec)
给非主键c2列创建索引,索引结构如下所示
二级索引和主键索引有如下区别
叶子节点数据页:主键索引存放的是完整用户记录,而二级索引存放的是c2列(非主键列)以及主键c1的值。
数据页之间排序和记录之间排序:按照c2列排序不再按照主键列排序。
目录项数据页:存放的是c2列值和数据页页号,不再是主键值和数据页页号。
看到这里不知道大家有没有这样的疑问,目录项数据页存放的是c2列值和数据页页号,但是c2列值不能保证唯一性(非主键,非唯一性)那么如下情况InnoDB如何确定叶子节点呢?
数据页8中c2值为7的有两个,如果这时需要插入一条记录,8
,7
,b
这时InnoDB根本无法确定插入到哪一个数据页,显然目录项数据页只存放c2列值和数据页页号是不够的,还需要主键值来确定唯一性,所以完整的二级索引结构应该如下所示
这样就可以得出8
,7
,b
这条记录正确存放的位置应该是页6。
InnoDB规定一个数据页最少存放两条记录!