对主键字段建立的索引叫做聚簇索引,对普通字段建立的索引叫做二级索引。
    那么多个普通字段组合在一起创建的索引就叫做联合索引,也叫组合索引。
    创建联合索引时,我们需要注意创建时的顺序问题,因为联合索引 (x, y, z) 和 (z, y, x) 在使用的时候会存在差别。
    联合索引要能正确使用需要遵循最左匹配原则,也就是按照最左优先的方式进行索引的匹配。
    比如,如果创建了一个 (a, b, c) 联合索引,如果查询条件是以下这几种,就可以匹配上联合索引:

    • where a=1;
    • where a=1 and b=2 and c=3;
    • where a=1 and b=2;

    需要注意的是,因为有查询优化器,所以 x 字段在 where 子句的顺序并不重要。
    但是,如果查询条件是以下这几种,因为不符合最左匹配原则,所以就无法匹配上联合索引,联合索引就会失效:

    • where b=2;
    • where c=3;
    • where b=2 and c=3;

    有一个比较特殊的查询条件:where a = 1 and c = 3 ,符合最左匹配吗?
    这种其实严格意义上来说是属于索引截断,不同版本处理方式也不一样。
    MySQL 5.5 的话,前面 a 会走索引,在联合索引找到主键值后,开始回表,到主键索引读取数据行,然后再比对 z 字段的值。
    从 MySQL5.6 之后,有一个索引下推功能,可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
    大概原理是:截断的字段会被下推到存储引擎层进行条件判断(因为 c 字段的值是在 (a, b, c) 联合索引里的),然后过滤出符合条件的数据后再返回给 Server 层。由于在引擎层就过滤掉大量的数据,无需再回表读取数据来进行判断,减少回表次数,从而提升了性能。
    比如下面这条 where a = 1 and c = 0 语句,我们可以从执行计划中的 Extra=Using index condition 使用了索引下推功能。
    联合索引非最左匹配 - 图1
    为什么联合索引不遵循最左匹配原则就会失效?
    原因是,在联合索引的情况下,数据是按照索引第一列排序,第一列数据相同时才会按照第二列排序。
    也就是说,如果我们想使用联合索引中尽可能多的列,查询条件中的各个列必须是联合索引中从最左边开始连续的列。如果我们仅仅按照第二列搜索,肯定无法走索引。