索引的出现就是为了提高查询的效率,就像一本书的目录。
对于一张表来说,索引其实就是它的目录。
(1)索引常见的模型
索引的出现是为了提高查询效率,但是实现索引的方式有很多种。
1.哈希表
哈希表是一种以键值对存储的数据结构,只要输入待查找的键(key),就可以找到其对应的值(value).
哈希表的实现思路很简单(数组+单链表),用一个哈希函数把key换算成一个确定的数组下标,然后把value值放入这个位置上,可能很多key值通过哈希算法会出现同一个值的情况(也就是在同一个下标位置上),会在链表上依次放入。
查找步骤是:先根据key算出确定的下标,然后在这个下标位置下的单链表上遍历查找!!!
缺点是:在区间查找效率慢(因为这个区间上的单链表都要全部遍历一遍)
哈希表这种结构适用于等值查询的场景(Nosql引擎等)
2.有序数组
因为是有序的,所以使用二分查找的效率很高,时间复杂度只有O( log(n))
同时这个索引结构支持范围查询,可以先用二分法查找左边界(如果是开区间,则找大于它的第一个数),再向右遍历知道找出第一个大于右边界的数,退出循环。
缺点:增删效率涉及大量元素移动,效率很低,所以不适合数据经常需要更新的
优点:查询效率最高
有序数组索引只适用于静态存储引擎(用于保存不会再修改的数据)
3.二叉搜索树
二叉搜索树的特点是:
父节点左子树的所有节点值小于父节点的值,右子数所有的结点值大于父节点的值。
搜索的时间复杂度是:O(log(n)),为了维持这个时间复杂度,需要保持这颗树是平衡二叉树,更新的时间复杂度也是O(log(n)).
在多叉树中,二叉树的搜索效率是最高的,但是大多数的数据库存储并不使用二叉树。
原因是:索引不止在内存中,还要写入磁盘上。
为了查询尽量少读磁盘,那么我们就不应该使用二叉树,而是要使用N叉树,N取决于数据块大小。
N叉树在读写上的性能优秀,以及适配磁盘访问模式,被广泛用于数据库引擎中。
(2)InnoDB存储引擎的索引模型
在MySql中,索引是在存储引擎层实现的,不同的存储引擎索引有不同的实现方式。
在InnoDB中,表都是根据主键顺序以索引的形式存放的,InnoDB使用了B+树索引模型,所有的数据都是存储在B+树中的。
每一个索引在数据库表中都对应一个B+树!!
索引类型分为:
主键索引:主键索引的叶子节点存的是整行数据。(就是除了主键索引之外的字段数据也在主键的B+树上)
非主键索引(二级索引):非主键索引的叶子节点存的是主键的值。
如果是使用主键索引的查询方式:(ID为主键索引,k为非主键索引)
select * from T where ID= 500;
则只需要搜索主键索引这颗B+树即可
如果使用非主键索引的查询方式:
select * from Twhere k = 2;
需要先搜索k索引这颗B+树找到主键,再搜索主键索引B+树。这个过程称为回表。
因为非主键索引要多扫描一课B+树,所以我们要尽量使用主键查询。
(3)索引维护
B+树为了维护索引的有序性,在插入新值的时候需要做必要的维护。
使用自增主键的插入数据模式,不会涉及挪动其他记录,也不会触发叶子节点的分裂。
主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。
所以从性能和存储空间方面考虑,自增主键往往是合理的选择!
有没有什么场景适合业务字段做主键的?
1.只有一个索引
2.该索引必须是唯一索引
(4)使用联合索引的技巧
1.覆盖索引:如果查询结果是联合索引的字段或查询结果为主键,则不用回表操作,直接返回结果。
2.最左前缀,联合索引的最左N个字段,也可以为字符串索引的最左M个字段
3.联合索引使用时要避免失效:
(1)在模糊查询的时候要避免以%开头
(2)使用or的时候要保证两边的字段都为索引,才会走索引,任意一个字段不为索引的话,另一个索引也会失效
(3)使用联合索引的时候没有使用左侧字段进行查询,索引会失效
(4)索引参与了运算或者使用了函数,则索引会失效