为什么需要索引
假设现在有100000条从0到10000且从大到小排列的整型数据,1条数据的大小假设(真的只是假设)是1KB,操作系统的每次I/O数据块(页)大小是8KB。 如果现在我要查找其中 50001 这个数据值,有如下几个方式: 1.最蠢的方式,遍历,每次遍历到一个值,就用这个值跟目标值做对比,如果不等于那么查找下一个。这样的话那么每次I/O是8条数据,目标数据在50001/8 约6600多次I/O 才能找到目标数据。 2.二分查找,最好一次性将100000条数据全部读到内存,这样查找也是很快的。
但是二分查找在这么多数据的情况下,由于没办法一次性全部将数据存入内存,也会导致多次的I/O,假设每一次取数据都在不同的I/O块中,那么一共也要有logn次。而且数据库不仅仅是单纯的查询,还有范围查询,模糊查询等等。所以要提高查询效率的关键,就在于如何减少读取磁盘块的次数,最好就是能控制在常数数量级
索引的原理
B+树
如上图,每个大框表示一个磁盘块,块中存放着多条索引记录,每条记录包含==键值+逻辑指针==(指向下一项索引块或数据块)
- 块中索引值是有顺序的,每个非终端节点中含有其子树的最大或最小值。
- 所有的叶子结点中包含了全部关键字的信息
- 叶子节点指针指向下一个叶子节点
查找60的过程
1.I/O第一次:读入5、28、65 数据块,在此同级别节点块上,60在28到65之间(其实是二分查找),那走P2指针指向的子树。 2.I/O第二次:读入28、35、56 数据块,在此同级别节点块上,60大于56,所以走P3指针指向的子树(上图中就是叶子节点)。 3.I/O第三次:读入叶子节点,在这个叶子节点中,使用二分查找算法找到目标值60。
这样就只需要三次io就能查到目标值。而这里有关于叶子节点是存放数据还是指向存放数据的页的指针的区别,即索引的类别
索引的分类
聚集索引
叶子节点也即数据节
。所有数据行的存储顺序与索引的存储顺序一致。所以一个表中只能存在一个聚集索引。一般都为主键值做索引,这也说明了为什么一个表只能有一个主键;
非聚集索引
常规使用的索引,叶子节点存放一个指针和偏移量,根据指针找到对应的数据块,再根据偏移量找到对应的数据行。新建一个索引时就会建立一颗新的索引树;
二者的比较
- 聚集索引比非聚集索引少一次I/o操作
- 当需要一定范围内的数据时,用聚集索引比用非聚集的好,因为聚集叶结点包含数据,相邻叶结点直接有指针指向,所以方便查询
- 新增数据,修改,删除的影响:聚集影响比非聚集的大,因为聚集索引的节点就带有所有数据,所以不管是插入时对唯一值,还是重新梳理树时,io的压力都会比非聚集索引大;
唯一索引
单个字段上建立唯一索引,需要此字段所在的列上不能有重复的值。 复合唯一索引:多个字段上联合建立唯一索引
覆盖索引
当某一查询中包含的所需字段皆包含于一个索引中,此时索引将大大提高查询性能。在建立索引的时候可以指定多个字段。
如果你在若干个字段上创建了一个复合的非聚集索引,且你的查询中所需Select字段及Where,Order By,Group By,Having子句中所涉及的字段都包含在索引中,则只搜索索引页即可满足查询,而不需要访问数据页。由于非聚集索引的叶结点包含所有数据行中的索引列值。
联合索引
联合索引也是一棵B+树,其键值数量大于等于2。键值都是排序的,通过叶子节点可以逻辑上顺序的读出所有数据。数据(1,1)(1,2)(2,1)(2,4)(3,1)(3,2)是按照(a,b)先比较a再比较b的顺序排列。
使用索引优劣
- 使用索引可以加快检索的速度,可以使IO的次数保持在常数级别
- 索引减低了插入、删除、修改等任务的速度,因为除了更新数据外,也要维护更新索引。
- 索引需要占用额外的物理空间;每次给字段建一个新索引, 字段中的数据就会被复制一份出来, 用于生成索引
索引的优化
- 为经常出现在查询中的字段,经常作表连接的字段以及经常出现在order by ,group by, distinct后面的字段建立索引。
- MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE(以“%(表示任意0个或多个字符)”开头的LIKE语句使索引失效)
- or语句前后没有同时使用索引时会使索引失效;可以使用union来代替。
- in 和 not in 也要慎用,否则会导致全表扫描
- 索引不应建立在长字段上。
- 应尽量避免
在 where 子句中对字段进行 null 值判断
,否则将导致引擎放弃使用索引而进行全表扫描 - 如果在
where 子句中使用参数
,也会导致全表扫描 - 应尽量避免在 where 子句中对字段进行
表达式操作
,这将导致引擎放弃使用索引而进行全表扫描 - 应尽量避免
在where子句中对字段进行函数操作
,这将导致引擎放弃使用索引而进行全表扫描。 - 字段值有大量重复时,如sex字段只有两个值,就算建立了索引也起不来优化的作用。
参考
https://www.cnblogs.com/morvenhuang/archive/2009/03/30/1425534.html
https://zhuanlan.zhihu.com/p/23624390
https://www.jianshu.com/p/814c1675361c
https://www.jianshu.com/p/e1dce41a6b2b
https://zhuanlan.zhihu.com/p/48385127