如果是MyISAM引擎,则直接根据索引树中记录的指针地址,直接触发磁盘IO再次读取数据即可。
3.3、写SQL执行时索引的维护过程
前面分析了查询SQL执行时,索引查找数据的过程,那当出现增、删、改SQL时呢?索引会怎么维护呢?其实这里也要分索引类型,如果是Hash结构的索引,直接增删改对应的索引键即可,但B+Tree结构的索引,因为要内部节点是有序的,所以需要维护有序性。
也就是代表着,插入、更改、删除数据时,都会对B+Tree索引造成影响。
但先说清一个误区,表中不同的索引在本地有不同的索引记录,比如ID、Name字段分别建立了两个索引,那么就会有两颗不同的索引树写入到本地磁盘文件中。
3.3.1、插入数据时索引的变化
B+Tree索引是有序的,对于这点在前面已经反复提到了,但如果索引字段是数值类型,例如int、bigint、long等,本身就能区分大小顺序,此时可以直接做排序工作。但如果是基于字符串或其他类型的字段建立索引呢?又该如何排序呀?其实对于这个问题也并不难回答,大家还记得在建库建表时,干的一件事情嘛?

在创建库表时,咱们通常都会指定一个排序规则,而这个规则就是MySQL对非数值类型字段的排序规则,比如字符串类型的字段,MySQL就会基于该规则对值先做计算处理,然后得到一个数值用于排序。
当然,具体排序处理的过程暂且不去纠结,重点只需搞清楚一点:数据库中任何字段都能排序即可。
OK~,那此时像数据库中插入一条数据时,还是以之前的用户表为例,比如:
INSERT INTO `zz_user` VALUES(6,"上海市黄浦区xx街道666号","棕熊","男",30);
复制代码
同样假设用户表上有两个索引,一是基于自增ID建立的主键索引,第二个则是基于姓名字段建立的普通索引。当表中插入这条数据后,索引又会发生什么变化呢?咱们分开聊聊。
主键/聚簇索引的变化
因为主键索引字段,也就是ID字段是顺序递增的,因此只需要在本地索引文件的B+Tree结构中,按照树结构找到最后的位置,将当前插入的ID:6作为索引键,以当前插入的行数据作为索引值,然后插入到最后的节点中即可。如下:

按序递增的索引维护,就是这么简单~
普通/非聚簇索引的变化
因为姓名字段本身的数据类型是字符串,与数值型字段天生的有序不同,字符串类型是无序的,因此首先需要根据已经配置好的排序规则,先对插入的name:棕熊这个值进行计算,然后根据计算出的值,决定当前数据在B+Tree中的索引位置,计算好之后再执行插入工作,过程如下:

相较于主键字段的顺序ID,插入字符串类型的name值会复杂一些,因为从这里可以明显看到,插入的“棕熊”数据经过计算后,它并不排最后面,而是排中间,所以要将这个值插入到对应的位置,此时树的节点就会发生裂变,后续的所有叶子节点都需要往后移动,这个开销是较大的。
同时,在插入索引信息时,会以“棕熊”作为索引键,以ID:6作为索引值,然后一同插入,也就是要与行数据建立关联(MyISAM引擎则是行数据的地址指针)。
3.3.2、删除数据时索引的变化
DELETE FROM `zz_user` WHERE ID = 5;
复制代码
例如上述这条删除语句,当执行后则会先根据ID在索引树中查找索引信息,然后先删除非聚簇索引上的索引信息,紧接着再去聚簇索引上删除主键索引信息和行数据。
过程大致是相同的,就不再制作动图演示其过程了,重点要记住的是:先删非聚簇索引信息,再删聚簇索引的信息,因为聚簇索引上存放着行数据,如果先把聚簇索引删了,就无法找到非聚簇索引上的信息了。