Mysql索引知识都在这儿了

92 阅读6分钟

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+树的叶子节点包含所有关键字,同时以有序链表的结构存储,可以很好的提高增删效率。