联合索引优点:
1、提高查询效率:多过滤条件查询的场景能大大提升查询效率,避免全表扫描;
2、减少索引占用空间:相比于单列的索引,虽然占用空间会大些,但多个单列索引会占用更大空间;
3、覆盖索引避免回表:在频率较高的查询场景可以建立组合索引,利用覆盖索引提升查询效率;
4、适用于多条件的索引查询;
联合索引内部结构:
从本质上来说,联合索引也是一棵 B+ 树,不同的是联合索引的键值的数量不是 1,而是大于等于 2。我们来看下两个整型列组成的联合索引,假定两个键值的名称分别为 a、b;
从图中可以看到多个键值的 B+ 树情况,键值都是排序的。通过叶子节点可以逻辑上顺序读取所有数据,就上面图中所示,即为 (1,1)、(1、2)、(2、1)、(2、4)、(3、1)、(3、2),数据是按照 (a, b) 的顺序进行存放,先对a排序再基于a排序的基础上对b排序。
最左前缀匹配:
MySQL联合索引遵循最左前缀匹配原则,即最左优先,查询的时候会优先匹配最左边的索引。
例如当我们在(a,b,c)三个字段上创建联合索引时,实际上是创建了三个索引,分别是(a)、(a,b)、(a,b,c)。
假设现在建立了一个(a,b,c)的联合索引,请判断下列是否用到索引:
select * from table where a=1; //可以走到索引(a)
select * from table where a=1 and b=2; //可以走到索引(a,b)
select * from table where a=1 and b=2 and c=3; //可以走到索引(a,b,c)
select * from table wherea=1 or b=2;//无法走到索引,仅当or前后的条件都能走到索引才可以,否则全表扫描;如select * from table where a=1 or (a=2 and b=3);可以走到索引
select * from table where b=2 and a=1; //a,b都能走到索引 (a,b),优化器会自动调整顺序
select * from table where c=3 and a=1; //仅a能走到索引
select * from table where c=3 and b=2; //都不能走到索引
select * from table where a =1 and b>2; //a、b能走到索引
select * from table where a=11 and b>2 and c=3; //a,b能走到索引,当遇到范围查询(>、<、between、like)就会停止匹配
结论:在 InnoDB 中联合索引只有先确定了前一个(左侧的值)后,才能确定下一个值。如果有范围查询的话,那么联合索引中使用范围查询的字段后的索引在该条 SQL 中都不会起作用。值得注意的是,in 和 = 都可以乱序,比如有索引(a,b,c),语句 select * from t where c =1 and a=1 and b=1,这样的语句也可以用到最左匹配,因为 MySQL 中有一个优化器,他会分析 SQL 语句,将其优化成索引可以匹配的形式,即 select * from t where a =1 and a=1 and c=1;
索引下推
最左前缀可以用于在索引中定位记录,那么,那些不符合最左前缀的部分,会怎么样呢?
以用户表的联合索引(name, age)为例,假设现在有一个需求,找出所有姓 “张” 并且 20 岁的男性:
select * from user where name like '张%' and age = 20 and sex = male
这条语句无法走到(name,age)的索引,仅能走到(name),因为联合索引中,如果查询中存在某个列的范围查询,则其右边所有列都无法使用索引进行加速查询;
具体来说,这个语句在搜索(name,age)的联合索引树的时候,并不会去看 age 的值,只是按顺序把 “name 第一个字是张” 的记录一条条取出来,然后开始回表,到主键索引上找出数据行,再一个一个判断其他条件是否满足。从下图可以看出来,需要回表 3 次。
这是 MySQL 5.6 之前的做法,简单总结,当进行索引查询时,首先根据索引来查找记录,然后再根据 where 条件来过滤记录
而 MySQL 5.6 开始,数据库在取出索引的同时,会根据 where 条件直接过滤掉不满足条件的记录,减少回表次数。这就是索引下推 (Index Condition Pushdown,ICP),一种根据索引进行查询的优化方式
从图中可以看出来,InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 20,对于不等于 20 的记录,直接判断并跳过,所以只需要对 ID1 这条记录进行回表判断就可以了。