(前置知识:最好知道联合索引覆盖索引是啥,不知道的话文章里也有简要定义可供参考学习 文章前半部分没什么代码和图片请见谅,最后会有一个清晰的综合案例验证,有基础的朋友可以直接跳转到最后的案例( ̄▽ ̄))
索引失效 和 不满足最左前缀匹配原则 的误区
我们在学习联合索引的时候知道,要使联合索引生效,必须满足"最左前缀匹配原则",即针对(a,b,c)
的联合索引,符合条件的字段只能是a
ab
abc
这三种最左前缀
案例1:查询条件是b=1 AND c=1;
bc
不属于以上三种,就不满足"最左前缀匹配原则" 案例2:查询条件是a=1 AND c=1;
这里的查询字段是ac
,只满足最左前缀a
,所以这个查询条件的a
是走联合索引的,而c
不走联合索引,仅作为过滤条件
以上的案例相信足够使你了解"最左前缀匹配原则"了,笔者当时学习的时候也是通过这两个案例了解的,但是也就是这里让笔者产生了一个很久之后才发现的误区: 在案例1中,不满足最左前缀匹配原则的查询,是否意味着在本次查询的时候是索引失效的?
先讲结论:不满足最左前缀匹配原则≠索引失效
当时笔者认为不满足"最左前缀匹配原则",不走索引,可不就是索引失效吗?其实不然,这里就要引出覆盖索引的概念了。
覆盖索引
覆盖索引并非是一种独立的索引类型,而是一种基于 联合索引 的 查询优化策略 (初学者谨记该定义) 覆盖索引要求我们查询的字段包含在联合索引中 ,比如联合索引是(a,b,c)
,而我们SELECT
的字段只有b,c
,这时候我们查询索引便可以直接获得数据,不用进行回表(不明白回表操作的可以先了解聚簇/非聚簇索引,明白了索引和数据存储的具体关系再来看)
为什么说"不满足最左前缀匹配原则≠索引失效"呢?原因就在覆盖索引,如果查询语句恰好 不满足最左前缀匹配原则 而 满足覆盖索引 那么即便我们不走联合索引,我们也会进行 全索引扫描 获取目标字段值,相比 全表扫描 更快,此时可认为索引仍然参与加速,不算严格索引失效
结合SQL代码进行案例分析
知道EXPLAIN
的用法,知道type
的的类型
EXPLAIN
:在 SQL 语句前添加 EXPLAIN,可分析查询的执行计划
type
(访问类型,性能核心指标):
const
:通过主键或唯一索引直接定位单行(最优)ref
:使用非唯一索引或联合索引前缀匹配(高效)range
:索引范围扫描(如BETWEEN
、>
)index
:全索引扫描(比全表快,但需优化)ALL
:全表扫描(需避免,除非数据量极小)
sql
-- 创建数据表
CREATE TABLE student (
id INT NOT NULL AUTO_INCREMENT COMMENT '自增主键',
s_name VARCHAR(50) NOT NULL COMMENT '姓名',
score1 INT COMMENT '分数1',
score2 INT COMMENT '分数2',
age INT COMMENT '年龄',
PRIMARY KEY (id), -- zizen主键
INDEX idx_name_score (a_name, score1, score2) -- 联合索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO student (s_name, score1, score2, age) VALUES
('张三', 34, 89, 20),
('李四', 72, 15, 19),
('王五', 95, 63, 22),
('赵六', 41, 78, 18),
('陈七', 56, 29, 21),
('刘芳', 88, 50, 20),
('周杰', 12, 94, 19),
('吴磊', 67, 38, 21),
('孙悦', 23, 81, 22),
('黄欣', 45, 72, 18),
('郑浩', 90, 11, 20),
('林静', 19, 85, 19),
('郭强', 83, 44, 21),
('何敏', 27, 66, 18),
('高飞', 50, 97, 22),
('徐丽', 61, 33, 20),
('马涛', 78, 55, 21),
('韩梅', 3, 89, 19),
('曹阳', 94, 22, 18),
('邓超', 38, 73, 22);
EXPLAIN SELECT * FROM student WHERE id=5; -- 执行结果:type:const / key:primary
EXPLAIN SELECT * FROM student WHERE s_name='邓超'; -- type:ref / key:idx_name_age
EXPLAIN SELECT * FROM student WHERE id>=5; -- type:range / key:primary
EXPLAIN SELECT score1,score2 FROM student WHERE score1>=60 AND score2>=60; -- type:index / key:idx_name_age
EXPLAIN SELECT score1,score2,age FROM student WHERE score1>=60 AND score2>=60; -- type:all / key:(NULL)
EXPLAIN SELECT score1,score2 FROM student WHERE score1>=60 AND score2>=60 and age>=20; -- type:all / key:(NULL)
EXPLAIN SELECT score1,score2,age FROM student WHERE score1>=60 AND score2>=60 and age>20; -- type:all / key:(NULL)
在以上的代码中我们创建了一张学生表,共5个字段:id,name,score1,score2,age 其中id为自增主键,(name,score1,score2)构成一个联合索引:
- 其中第四条语句,就是本文前面的不满足最左前缀匹配原则≠索引失效的案例,虽然where条件不符合最左前缀匹配原则,但是走的全索引扫描,不算索引失效
- 而第五句多查了个age,不在联合索引中,就是既不满足最左前缀匹配原则,又不满足覆盖索引,这种才算索引失效
笔者较菜,第一次写文章,内容不长,复习MySQL索引时有感而发,进行分享记录,感谢阅读支持(●'◡'●)