深入浅出索引
索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本500页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,估计可得找一会。同样,对于数据库的表而言,索引其实就是的它的目录。
索引的常见模型
1、哈希表,是一种以键-值(key-value)存储数据的结构,我们只要输入待查找的值即key,就可以找到其对应的值即value。哈希的思路很简单,把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置。
2、有序数组,在等值查询和范围查询场景中的性能就都非常优秀。有序数组索引只适用于静态存储引擎,比如你要保持的是2017某个城市的所有人口信息,这类不会再修改的数据。
3、搜索树。N叉树由于在读写上的性能有点,以及适配磁盘的访问模式,已经被广泛应用在数据库引擎中。
不管是哈希还是有序数组,或者N叉树,它们都是不断迭代、不断优化的产物或者解决方案。数据库技术发展到今天,跳表、LSM树等数据结构也被用于引擎设计中。数据库底层存储的核心就是基于这些数据模型的,每碰到一个新的数据库,我们需要先关注它的数据模型,这样才能从理论上分析出这个数据库的使用场景。
InnoDB的索引模型
在InnoDB中,表都是根据主键顺序以索引的形式存放的,这个存储方式的表成为索引组织表。InnoDB使用了B+树索引模型,所以数据都是存储在B+树种的。每一个索引在InnoDB里面对应一个B+树。
如下图可见,基于主键索引和普通索引的查询区别在于,普通索引的查询需要多扫描一个搜索树。因此,我们在应用中应该尽量使用主键查询。
索引维护
B+树为了维护索引的有序性,在插入新值的时候需要做必要的维护。以上面这个为例,如果插入新的行ID值为700,则只需要在R5的记录后面插入一个新记录。如果新插入的ID值为400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。而更槽的情况是,如果R5所在的数据也已经满了,根据B+树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去,这个过程称为页分裂。在这个情况下,性能自然会受影响。
除了性能外,页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约50%。当然有分裂就有合并。当相邻的两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。
所以,从性能和存储空间方面考量,自增主键往往是更合理的选择。
覆盖索引
由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
最左前缀原则
B+树这种索引结构,可以利用索引的“最左前缀”,来定位记录。
索引下推
索引下推优化,可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。