1. 最左前缀匹配原则示例
1.1. 数据准备
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) NULL DEFAULT NULL,
`b` int(11) NULL DEFAULT NULL,
`c` int(11) NULL DEFAULT NULL,
`d` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_abc`(`a`, `b`, `c`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t1` VALUES (1, 13, 12, 4, 'dll');
INSERT INTO `t1` VALUES (2, 1, 5, 4, 'doc');
INSERT INTO `t1` VALUES (3, 13, 16, 5, 'img');
INSERT INTO `t1` VALUES (4, 12, 14, 3, 'xml');
INSERT INTO `t1` VALUES (5, 1, 1, 4, 'txt');
INSERT INTO `t1` VALUES (6, 13, 16, 1, 'exe');
INSERT INTO `t1` VALUES (7, 5, 3, 6, 'pdf');
建立 a、b、c 三列的联合索引 index_abc ,数据表数据如下图

1.2. 全值匹配查询
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'
......
3 条 SQL 语句都用到了联合索引。where 子句几个搜索条件顺序调换不影响查询结果,因为 MySQL 中有查询优化器,会自动优化查询顺序*
1.3. 匹配左边的列
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'
都从最左边开始连续匹配,3 条 SQL 语句都用到了联合索引
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 和 c 列可以匹配,但 b 列无法匹配,所以没没有使用到联合索引
1.4. 匹配前缀列
如果列是字符型的话它的比较规则是先比较字符串的第一个字符,第一个字符小的哪个字符串就比较小,如果两个字符串第一个字符相同,那就再比较第二个字符,第二个字符比较小的那个字符串就比较小,依次类推,比较字符串
如果 a 是字符类型,那么前缀匹配用的是索引,后缀和中缀只能全表扫描了
select * from table_name where a like 'As%';
select * from table_name where a like '%As';
select * from table_name where a like '%As%';
1.5. 匹配纯范围查询
1.5.1. 联合索引第一列范围查询
1.5.1.1. 案例一
SELECT * FROM t1 WHERE a > 1
EXPLAIN 执行计划说明 没有使用到联合索引,是全表扫描- 最左优先,以最左边的为起点任何连续的索引都能匹配上,但遇到范围查询
>、<、between、like 就会停止匹配

1.5.1.2. 案例二
SELECT * FROM t1 WHERE a > 1 AND a < 12
可以对最左边的列进行范围查询,可以用到联合索引。EXPLAIN 执行计划如下图
 执行计划中的 type 字段是 range ,它指的是:它是索引上的范围查询,它会在索引上扫描特定范围内的值
1.5.2. 联合索引第一、二列同时范围查询
SELECT * FROM t1 WHERE a > 1 AND a < 12 AND b > 1
虽然在 1 < a < 12 的范围内 b 是无序的,但 b 字段由于是范围查询,所以找到 1< a < 12 的记录后,可以根据条件 b > 1 继续范围过滤查找,是可以用到联合索引的

1.5.3. 联合索引第一、二、三列同时范围查询
SELECT * FROM t1 WHERE a > 1 AND b > 3 AND c > 2
第一、二、三列同时范围查询, 没有使用到联合索引,是全表扫描

1.6. 精确查询某一列并范围查询另外一列
1.6.1. 案例一
如果左边的列是精确查找的,右边的列可以进行范围查找
SELECT * FROM t1 WHERE a = 1 AND b > 3;
a = 1 的情况下 b 是有序的,进行范围查找走的是联合索引

1.6.2. 案例二
SELECT * FROM t1 WHERE a = 1 AND b > 3 AND c = 4
虽然 b > 3 是范围查询,但 EXPLAIN 执行计划说明依然使用的是联合索引

1.6.3. 案例三
SELECT * FROM t1 WHERE a = 1 AND b > 3 AND c > 2
虽然 b > 3 和 c > 2 是范围查询,但 EXPLAIN 执行计划说明依然使用的是联合索引

1.6.4. 案例四
SELECT * FROM t1 WHERE a = 1 AND b =5 AND c > 2
EXPLAIN 执行计划说明依然 使用的是联合索引

|