MySQL联合索引之索引失效与否

目录

  • 1. 最左前缀匹配原则示例
    • 1.1. 数据准备
    • 1.2. 全值匹配查询
    • 1.3. 匹配左边的列
    • 1.4. 匹配前缀列
    • 1.5. 匹配纯范围查询
      • 1.5.1. 联合索引第一列范围查询
        • 1.5.1.1. 案例一
        • 1.5.1.2. 案例二
      • 1.5.2. 联合索引第一、二列同时范围查询
      • 1.5.3. 联合索引第一、二、三列同时范围查询
    • 1.6. 精确查询某一列并范围查询另外一列
      • 1.6.1. 案例一
      • 1.6.2. 案例二
      • 1.6.3. 案例三
      • 1.6.4. 案例四

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,数据表数据如下图

MySQL联合索引之索引失效与否_第1张图片

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' 
......

3SQL 语句都用到了联合索引。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'

都从最左边开始连续匹配,3SQL 语句都用到了联合索引

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' 

如果查询字段不连续时, 虽然 ac 列可以匹配,但 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 就会停止匹配

MySQL联合索引之索引失效与否_第2张图片

1.5.1.2. 案例二

SELECT * FROM t1 WHERE  a > 1 AND a < 12

可以对最左边的列进行范围查询,可以用到联合索引。EXPLAIN 执行计划如下图

MySQL联合索引之索引失效与否_第3张图片
执行计划中的 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 继续范围过滤查找,是可以用到联合索引的

MySQL联合索引之索引失效与否_第4张图片

1.5.3. 联合索引第一、二、三列同时范围查询

SELECT * FROM t1 WHERE  a > 1 AND  b > 3 AND c > 2 

第一、二、三列同时范围查询, 没有使用到联合索引,是全表扫描

MySQL联合索引之索引失效与否_第5张图片

1.6. 精确查询某一列并范围查询另外一列

1.6.1. 案例一

如果左边的列是精确查找的,右边的列可以进行范围查找

SELECT * FROM t1 WHERE  a = 1 AND b > 3;

a = 1 的情况下 b 是有序的,进行范围查找走的是联合索引

MySQL联合索引之索引失效与否_第6张图片

1.6.2. 案例二

SELECT * FROM t1 WHERE  a = 1 AND b > 3 AND c = 4

虽然 b > 3 是范围查询,但 EXPLAIN 执行计划说明依然使用的是联合索引

MySQL联合索引之索引失效与否_第7张图片

1.6.3. 案例三

SELECT * FROM t1 WHERE  a = 1 AND b > 3 AND c > 2

虽然 b > 3c > 2 是范围查询,但 EXPLAIN 执行计划说明依然使用的是联合索引

MySQL联合索引之索引失效与否_第8张图片

1.6.4. 案例四

SELECT * FROM t1 WHERE  a = 1 AND b =5 AND c > 2

EXPLAIN 执行计划说明依然 使用的是联合索引

MySQL联合索引之索引失效与否_第9张图片

你可能感兴趣的:(数据库,#,mysql,mysql)