联合索引的组织形式

从本质上来说,联合索引也是一个B+树,和单值索引不同的是,联合索引的键值对不是1个,而是多个。下图是一个a、b字段联合索引的B+树结构:

image-20210423184201196

可以发现a字段是有序排列,b字段是无序排列(因为B+树只能选一个字段来构建有序的树),但是在a相等的情况下,b字段是有序的,可以说b的有序是建立在a有序的基础上的。多字段下以此类推,这是MySQL索引匹配的基础。

  • a顺序:1,1,1,2,3,3
  • b顺序:1,2,3,4,1,2

对于select * from testTable where a=1 and b=2; 首先在a=1的情况下,结果是(1,1)(1,2),再在此基础上查找b=2的数据,即(1,2)。即首先a字段在B+树上是有序的,所以我们可以通过二分查找法来定位到a=1的位置。其次在a确定的情况下,b是相对有序的,因为有序,所以同样可以通过二分查找法找到b=2的位置。

对于select * from testTable where b=2; 由于b的排序:1,2,3,4,1,2,在没有a作为前提的情况下,b的排序是无序的,因此是用不上索引的。也就是我们常说的违背了最左匹配原则

范围查询失效

对于以下查询:

select * from testTable where a>1 and b=2;

讲一下匹配过程:首先匹配a字段,二分查找法定位到1,然后将所有大于1的数据取出来,a>1的结果有a=2,a=3。

image-20210423184222678

列出a=2和a=3时b的排序:4,1,2,是无序的,所以b不能在无序的B+树里用二分查找来查询,b用不到索引。

b用不到索引表现出来的结果就是索引失效。

like索引失效

我们先来了解一下%的用途

  • %放在右边,代表查询以”a”开头的数据,如:abc。
  • 两个%%,代表查询数据中包含”a”的数据,如:cab、cba、abc。
  • %放在左边,代表查询以”a”为结尾的数据,如cba。

%号放右边(前缀)

先来康康B+树对于字符串索引的组织方式:先按照第一个字母排序,如果第一个字母相同,就按照第二个字母排序。。。以此类推。

image-20210423170742233

由于B+树的索引顺序,是按照首字母的大小进行排序,前缀匹配又是匹配首字母。所以可以在B+树上进行有序的查找,查找首字母符合要求的数据,因此可以用到索引。

%号放左边

是匹配字符串尾部的数据,我们上面说了排序规则,尾部的字母是没有顺序的,所以不能按照索引顺序查询,就用不到索引。

两个%%号

这个是查询任意位置的字母满足条件即可,只有首字母是进行索引排序的,其他位置的字母都是相对无序的,所以查找任意位置的字母是用不上索引的。

索引列上进行运算导致索引失效

索引失效的原因是索引是针对原值建的B+树,将列值计算后,原来的二叉树就用不上了。

类型转换导致索引失效

类型都不同了,自然没法匹配。

OR 索引失效

where a=1 or b=1;

此时a、b的顺序:

  • a顺序:1,1,2,2,3,3
  • b顺序:1,2,3,4,1,2

这个联合索引对b来说是无序的,没法进行最左匹配 索引失效

IN 索引失效

根据实际的情况,需要控制IN查询的范围。原因有以下几点

  • IN 的条件过多,会导致索引失效,走索引扫描
  • IN 的条件过多,返回的数据会很多,可能会导致应用堆内内存溢出。

所以必须要控制好IN的查询个数。主要还是由Mysql优化器根据成本来判断的, 是走索引还是不走, 两相权衡。

⭐️什么情况下会发生明明创建了索引,但是执行的时候并没有通过索引呢?

在一条单表查询语句真正执行之前,MySQL的查询优化器会找出执行该语句所有可能使用的方案,对比之后找出成本最低的方案。这个成本最低的方案就是所谓的执行计划。优化过程大致如下:

1、根据搜索条件,找出所有可能使用的索引 2、计算全表扫描的代价 3、计算使用不同索引执行查询的代价 4、对比各种执行方案的代价,找出成本最低的那一个 。

当使用mysql非主键索引进行查询时,如果扫描数据量接近全表数据量时,mysql会进行全表扫描不会使用索引(主键索引除外),这也是为什么不建议在区分度低的字段上建索引,也会导致全表扫描。 rows不能直接理解为扫描行数, 表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数,实际就是mysql根据估算的所需读取的行数决定是全表扫描还是使用索引。