1. 数据库索引
数据库索引就是对表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。
数据库索引是非常重要的概念,它能帮助存储引擎快速定位记录,对于提升数据库的性能、减轻数据库服务器的负担有着非常重要的作用。
(1) 索引的分类
1) 聚集索引
聚集索引是指数据行的物理顺序与键值(一般是主键)的逻辑顺序相同。
一个表中只能拥有一个聚集索引,因为一个表的物理顺序只有一种情况。
有的资料中说,聚集索引就是主键索引,这是不正确的。
事实上,只是某些库(比如SQL Server)是默认在主键上建立聚集索引而已,甚至可以在建立主键的时候声明为非聚集索引,具体可以参考下这篇文章中的实践。
有人把聚集索引比作使用拼音目录来查字典,每个字存放的页码就是数据的物理地址。
从上图可以看到,聚集索引的叶子节点就是对应的数据节点,可以直接获取到对应的全部列的数据。
2) 非聚集索引
如果某索引不是聚集索引,则表中的行物理顺序与索引顺序不匹配,这就是非聚集索引。
有人把非聚集索引比作使用偏旁部首来查字典,它的结构顺序与实际存放顺序不一定一致。
从上图可以看到,非聚集索引的叶子节点仍然是索引节点,此如果使用非聚集索引查询,而查询列中包含了其他该索引没有覆盖的列,那么他还要进行第二次的查询,查询节点上对应的数据行的数据。因此,在查询方面,它会比聚集索引慢。
3) 覆盖索引
非聚集索引和聚集索引的区别在于,通过聚集索引可以查到需要查找的数据,而通过非聚集索引可以查到记录对应的主键值 ,再使用主键的值通过聚集索引查找到需要的数据(InnoDB的非覆盖索引的叶子结点存储的是主键的值,而MyISAM存储的是记录指针)。
也就是说,对于InnoDB来说,它们最终都会利用主键通过聚集索引来定位到数据。但是如果说聚集索引是通往真实数据所在的唯一路径也是不正确的,因为还有一种索引 —— 覆盖索引。
覆盖索引是进行SQL优化的重要方式,最常见的方式就是将被查询的字段,建立到一个联合索引中去(被查询的列要被所建的索引覆盖,所以叫覆盖索引)。也就是说,如果一个节点上包含了所有要查的值,那就不需要回表进行二次查询,直接返回即可。
建立的联合索引遵循最左匹配原则,具体的规则可以看这篇文章。
(2) 索引的原理
关于索引的原理,这篇文章讲的十分通俗易懂。
聚集索引和非聚集索引,都是采用平衡树作为索引的数据结构(当然也有用Hash的,但是主流的数据库都是把平衡树当作数据表默认的索引数据结构的)。
索引的原理说白了就是,把字段中的数据复制出来,存放在索引树中。索引树中各节点的值来自于表中的索引字段,假如给 user 表的 name 字段加上索引,那么索引就是由 name 字段中的值构成。
如果给表中多个字段加上索引,那么就会出现多个独立的索引结构,每个索引(非聚集索引)互相之间不存在关联。每次给字段建一个新索引,字段中的数据就会被复制一份出来,用于生成索引。因此,给表添加索引,会增加表的体积,占用磁盘存储空间。
索引能让数据库查询数据的速度上升,同时也会使得写入数据的速度下降。增删改数据都会改变平衡树各节点中的索引数据内容,破坏树结构,在数据改变时,数据库需要一直维护索引结构的正确性。这会带来不小的性能开销,也就是为什么索引会给查询以外的操作带来副作用的原因。
如果想更清楚地了解这个过程,可以看这篇文章。
(3) 索引的数据结构
上边介绍过,索引一般采用平衡树作为数据结构。
平衡树指的是,其任意节点的左右子树的高度差都不大于1的树。
平衡树有很多分类,比如最简单的二叉平衡树Treap,以及多路平衡树B树、B+树等等。而数据库索引一般使用的是多路平衡树。
1) B树
B树与二叉平衡树相比,它的每一个非叶子节点可以有多个子树,因此,当总节点数相同时,B树的高度远小于二叉平衡树。也就是说,B树是一颗又矮又胖的树。
理论上说,二叉平衡树的查询时间复杂度是O(log N),其效率已经足够高了,为什么不直接使用二叉平衡树而是使用B树呢?
其实这是由于磁盘IO导致的。
众所周知,内存是比较昂贵的,因此在大数据量场景下,不可能把所有的数据一次性加载到内存中,只能逐一加载磁盘页,每个磁盘页就对应树的每个节点。而如果树的高度太高,会造成频繁的磁盘IO操作,导致效率低下。
平衡树的特点是, B树和B+树
2) B+树
B+树也是多路平衡查找树,其与B树的区别主要在于:
-
B树中每个节点(包括叶节点和非叶节点)都存储真实的数据,B+树中只有叶子节点存储真实的数据,非叶节点只存储键。在MySQL中,这里所说的真实数据,可能是行的全部数据(如Innodb的聚簇索引),也可能只是行的主键(如Innodb的辅助索引),或者是行所在的地址(如MyIsam的非聚簇索引)。
-
B树中一条记录只会出现一次,不会重复出现,而B+树的键则可能重复重现——一定会在叶节点出现,也可能在非叶节点重复出现。
-
B+树的叶节点之间通过双向链表链接。
-
B树中的非叶节点,记录数比子节点个数少1;而B+树中记录数与子节点个数相同。 由此,B+树与B树相比,有以下优势:
-
更少的IO次数:B+树的非叶节点只包含键,而不包含真实数据,因此每个节点存储的记录个数比B数多很多(即阶m更大),因此B+树的高度更低,访问时所需要的IO次数更少。此外,由于每个节点存储的记录数更多,所以对访问局部性原理的利用更好,缓存命中率更高。
-
更适于范围查询:在B树中进行范围查询时,首先找到要查找的下限,然后对B树进行中序遍历,直到找到查找的上限;而B+树的范围查询,只需要对链表进行遍历即可。
-
更稳定的查询效率:B树的查询时间复杂度在1到树高之间(分别对应记录在根节点和叶节点),而B+树的查询复杂度则稳定为树高,因为所有数据都在叶节点。
B+树也存在劣势:由于键会重复出现,因此会占用更多的空间。
但是与带来的性能优势相比,空间劣势往往可以接受,因此B+树的在数据库中的使用比B树更加广泛。
参考引用
MySQL聚集索引和非聚集索引:www.cnblogs.com/starcrm/p/1…
聚集索引和非聚集索引的总结:www.cnblogs.com/s-b-b/p/833…
主键索引就是聚集索引吗:www.cnblogs.com/aspirant/p/…
输入浅出数据库索引原理:www.cnblogs.com/aspwebchh/p…
MySQL的覆盖索引与回表:zhuanlan.zhihu.com/p/107125866
b树时间复杂度是多少:blog.csdn.net/weixin_3212…
简单剖析B树与B+树:blog.csdn.net/z_ryan/arti…