有mysql联合索引(A, B, C),那么AC查询会用到索引吗?

  提到联合索引的使用规则,一般我们都会想到左匹配原则,为什么是左不是右呢?这是因为即使是联合索引在innodb底层也是使用b+树来存放的,各个节点排序的规则就是按照联合索引中多个字段从左往右依次排序的,所以查询的时候需要左匹配才能保证b+树中的数据是有序的,才能查询;如果单独查询最右侧字段,那么其在b+索引树里面是完全无序的,自然也就无法查询。

  那么有这样一个问题,架设联合索引idx_a_b_c(a, b, c),其中针对a和c两个字段进行查询是否能够使用索引呢?大家可以先暂停,自己思考一下~

  

  相信大家经过思考已经有了自己的答案,那么我们一起去探索求证一下吧。  

  我这里使用的mysql版本为5.7.25

  首先,我们创建一张表:将字段a,b,c设置为联合索引。

create table `my_index_test` (
	`id` int(11) unsigned not null auto_increment comment '主键id',
	`column_a` int(11) unsigned not null default 0 comment '字段a',
	`column_b` int(11) unsigned not null default 0 comment '字段b',
	`column_c` int(11) unsigned not null default 0 comment '字段c',
	`column_d` int(11) unsigned not null default 0 comment '字段d',
	primary key (`id`),
	key `idx_a_b_c` (`column_a`, `column_b`, `column_c`)
) ENGINE=InnoDB comment="联合索引测试";

  我们再插入一些测试数据

DELIMITER //
CREATE PROCEDURE batch_insert()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 10000 DO
	INSERT INTO my_index_test(column_a,column_b,column_c,column_d) VALUES(i,i,i,i);
SET i=i+1;
END WHILE;
END;
// 


call batch_insert();

  接下来我们分析一下查询语句:

  1. 首先我们来看常规的a,b,c查询:

  

   可以发现正常使用到了联合索引,在我们的意料之中

 

  2. 我们再来看一下b,c查询:

  

  这里大家要注意了,可能些同学看到explain语句分析的结果中key为idx_a_b_c就认为这条查询语句使用到了索引,觉得效率很高,更重要的b,c查询不符合左匹配的原则,为什么还会用到索引呢?这里稍微解释一下type字段,在这个例子中我们看到type为index,它的意思是对索引进行全表扫描,在上面的例子中就是对idx_a_b_c索引进行全扫描,索引中的数据量是等于全表数据量的,换句话说type为index是另一种形式的全表扫描。

  有同学可能会问那么innodb为什么会这么干呢?稍微在扩展一下:

  这是因为我们select的字段"column_a"是存在于索引上,不需要回表再去查的。所以innodb引擎判断直接在idx_a_b_c上进行全扫描即可完成任务,并且比在聚簇索引上进行全表扫描会更加节省内存,更加快速。如果我把语句改为“select column_d from my_index_test where column_b=3 and column_c = 1”,注意“column_d”字段不在任何索引上。

  

  可以发现这次已经是type=all全表扫描了。有上述疑惑的同学们这下应该理解了吧~

 

  好了我们言归正传,来验证下最初的问题a,c会使用到索引吗?

  

  可以看到a,c查询也是会用到idx_a_b_c索引的。

  如何理解这个结果呢?开篇我们已经说过了联合索引在innodb底层的存储和排序方式:数据首先在a字段的维度进行排序,然后在b字段维度排序,最后是c字段,从左向右依次类推,最终存放在b+树里。如果搜索条件是a,c的话,虽然c在结果区间是无序的(中间有一层b),但是单单是用a字段就可以把结果区间圈定在一个很小的范围内,肯定是比全表扫描需要遍历的字段要少对吧。

  至于为什么网上去查资料很多都是a,c不支持的回答,想必是早期的innodb版本没有把优化做到这一步,还有待看源码确认,但是相信像能够阅读到这的优秀同学如果看到innodb居然不支持a,c使用联合索引,也会想着亲自去优化innodb的吧~

  

 

 

 

 

 

 

  

 

posted @ 2021-07-06 17:19  Cgj20060102030405  阅读(7762)  评论(0编辑  收藏  举报