1,什么是索引
索引是帮助Mysql高效查询数据的数据结构。
2,索引的优势和劣势
优势:
-
提升数据检索的效率,降低数据库的IO成本,类似于书本的目录。
-
通过索引列对数据进行排序,降低数据排序的成本,降低cpu的损耗。
a:被索引的列会自动进行排序。
b:如果按照索引列的顺序来排序,那么对应order by来说效率就会提高很多。
劣势:
-
索引会额外占据磁盘空间。
-
索引虽然会提高查询效率,但是会降低更新表的效率。每次mysql对数据进行增删改操作,不仅要保存数据,也要保存和更新对应的索引文件。
3,索引的类型
普通索引,主键索引,唯一索引,组合索引,全文索引。
4,索引的数据类型
Mysql索引默认使用B+树的数据结构。
4.1 B+ Tree索引和Hash索引的区别:
哈希索引适合等值查询,不适合范围查询;
哈希索引没有办法利用索引完成排序;
哈希索引不支持多列组合索引的最左匹配原则;
如果有大量重复的键值数据,哈希索引的效率就非常低,因为存在哈希碰撞问题。
4.2 聚族索引和非聚聚族索引
在InnoDB中,索引B+ Tree的叶子节点存储了整行数据的主键索引,也称聚族索引。而B+ Tree的叶子节点存储了数据的主键值是非主键索引,也称非聚族索引。
两者的区别:
聚族索引查询更快。
为什么呢?
因为聚族索引的叶子节点就是我们要查询的整行数据,而非聚族索引的叶子节点是主键的值,还要回表再查询一次。
那是所有的情况都是这样吗?
不是,当覆盖索引查询时,只需要查一次。
5,覆盖索引
覆盖索引是指,当数据查询语句从索引中就能获得,不需要从数据表中获得。
当一条查询语句满足覆盖索引的条件,从索引中就能获取数据,这样避免了查到索引还要去数据表中查询的操作,减少IO提高效率。
6,最左匹配原则
当查询经常用到多个字段时,可以建立组合索引来提高查询效率。
组合索引对比单个多字段索引的区别:
a:减小开销:例如创建col1,col2,col3的组合索引,相当于创建了(col1),(col1,col2),(col1,col2,col3)三个索引。
b:覆盖索引:如果查询的字段都在索引中,那么就不需要回表查询操作。
c:效率高:组合索引比单索引的效率更高。
当查询条件的列中包含组合索引的最左边的那一列,不管该列在查询条件中的任意位置,都会使用到索引。所以,当查询中不包含组合索引的最左边那一列,则不会使用此组合索引。
索引的底层是B+树,组合索引当然也是B+树。构建一颗B+树只能以一个字段来构建,因此数据库依据组合索引最左边的字段来构建。
例子:比如有一个联合索引(a,b),那么一颗B+树索引结构就如下图所示。
图来自网上
可以看到,a的值是有序的,1,1,2,2,3,3,而b的值是无序的,1,2,1,4,1,2。所以b=2这种是没有办法利用索引的,因为联合索引是按a排序的,b是无序的。
同时还可以发现a在等值的情况下,b是有序的,但这种有序是相对的。所以当最左匹配原则遇上范围查询就会停止,剩下的字段都无法用到索引。
最左匹配原则:最左优先,以最左边为起点的任何连续索引都能匹配上,同时遇到范围(>,<,between and,like)查询,后续索引都用不到。
通过举例,加深理解。
例如,建立索引(a,b,c)
6.1,全值匹配
select * from table_name where a = '1' and b = '2' and c = '3'
select * from table_name where b = '2' and a = '1' and c = '3'
select * from table_name where c = '3' and b = '2' and a = '1'
用到了索引,where子句中顺序不影响查询结果,因为mysql有查询优化器,会自动优化查询顺序。
6.2,匹配左边的列
select * from table_name where a = '1'
select * from table_name where a = '1' and b = '2'
select * from table_name where a = '1' and b = '2' and c = '3'
用到了索引。
select * from table_name where b = '2'
select * from table_name where c = '3'
select * from table_name where b = '1' and c = '3'
没有用到索引,因为没有从最左边开始。
select * from table_name where a = '1' and c = '3'
这种就只有a用到了索引,b和c没有用到索引。
6.3,匹配列前缀
select * from table_name where a like 'As%'; //前缀都是排好序的,走索引查询
select * from table_name where a like '%As'//全表查询
select * from table_name where a like '%As%'//全表查询
6.4,匹配范围值
select * from table_name where a > 1 and a < 3
可以对最左边字段进行范围查询。
select * from table_name where a > 1 and a < 3 and b > 1;
当对多个列进行范围查询时,只能对最左边列的范围查询用到索引。其他字段索引失效。在1<a<3中,b是无序的,不能用到索引。
6.5,精确匹配某一列,并范围查询另一列
如果左边的列是精确查找,那么右边的列可以用到范围查询。
select * from table_name where a = 1 and b > 3;
当a = 1时,b是有序的,范围查询走的是到联合索引。
6.6,排序
Mysql把内存在内存或磁盘中进行排序的方式,统称为文件排序。文件排序非常慢,如果order by子句中用到了索引列,就有可能省略文件排序的步骤。
select * from table_name order by a,b,c limit 10;
因为B+树索引本身就是按照上述规则进行排序的。
order by的顺序必须同联合索引的顺序一致,否则不生效。
select * from table_name order by b,c,a limit 10;
这种排序就没有用到索引排序。
select * from table_name order by a limit 10;
select * from table_name order by a,b limit 10;
这种用到部分索引。
select * from table_name where a =1 order by b,c limit 10;
联合索引左边列是常量,右边的列排序用到了索引。
7,B树和B+树的对比
7.1,区别:
B树的内部结点和叶子结点都存储键和值,B+树内部结点只存储键,不存储值,在叶子结点存储键和值;
B树叶子结点是相互独立的,B+树叶子结点有一条链相连。
\
B树的好处:
由于B树的内部结点同时存储了键和值,因此将频繁访问的数据放到靠近根结点的地方,将大大提高热点数据的查询效率。这种特效使得B树在特定数据重复多次的场景将更加高效。
B+树的好处:
空间利用率更高,减少IO次数,磁盘独享代价更低;B+树的查询效率更稳定;支持随机检索和顺序检索;
7.2,为什么B+树比B树更适合实际应用的操作系统文件索引和数据库索引呢?
1)B树只适合随机检索,B+树同时适合随机检索和顺序检索。
2)B+的空间利用率更高,减少IO次数,磁盘读写代价更低。
B+的内部节点并没有指向关键字具体信息的指针,因此其内部节点比B树更小。
如果把所有相同的内部节点的关键字存放到同一盘块中,那么盘块所容纳的关键字数量也就越多,一次性读入到内存所需要查找的关键字信息也就越多。这样减少了IO查询次数。
3)B+树的查询效率更稳定。
由于非终点结点不是指向最终文件内容的指针,而是叶子结点关键字的索引。所有关键字据的查找必须走一条从根结点到叶子结点的路。所有关键字查找的路径长度相同,导致每一个数据的查询效率相当。
4)B树在提高了IO性能的同时并没有解决元素遍历效率低下的问题。B+树的叶子结点是有一条指针顺序相连,只要遍历叶子结点就可以实现遍历整棵树。数据库的范围查询是非常频繁的,而B树是不支持这样的操作。
5)增删文件(节点)时,B+树的效率更高。
B+树的叶子节点包含所有关键字,同时以有序链表的结构存储,可以很好的提高增删效率。