【MySQL】联合索引和覆盖索引(索引失效的误区讲解+案例分析)

(前置知识:最好知道联合索引覆盖索引是啥,不知道的话文章里也有简要定义可供参考学习 文章前半部分没什么代码和图片请见谅,最后会有一个清晰的综合案例验证,有基础的朋友可以直接跳转到最后的案例( ̄▽ ̄))

索引失效 和 不满足最左前缀匹配原则 的误区

我们在学习联合索引的时候知道,要使联合索引生效,必须满足"最左前缀匹配原则",即针对(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索引时有感而发,进行分享记录,感谢阅读支持(●'◡'●)

相关推荐
技术宝哥2 小时前
Redis(2):Redis + Lua为什么可以实现原子性
数据库·redis·lua
学地理的小胖砸4 小时前
【Python 操作 MySQL 数据库】
数据库·python·mysql
dddaidai1234 小时前
Redis解析
数据库·redis·缓存
数据库幼崽4 小时前
MySQL 8.0 OCP 1Z0-908 121-130题
数据库·mysql·ocp
Amctwd4 小时前
【SQL】如何在 SQL 中统计结构化字符串的特征频率
数据库·sql
betazhou5 小时前
基于Linux环境实现Oracle goldengate远程抽取MySQL同步数据到MySQL
linux·数据库·mysql·oracle·ogg
lyrhhhhhhhh5 小时前
Spring 框架 JDBC 模板技术详解
java·数据库·spring
喝醉的小喵7 小时前
【mysql】并发 Insert 的死锁问题 第二弹
数据库·后端·mysql·死锁
付出不多7 小时前
Linux——mysql主从复制与读写分离
数据库·mysql
初次见面我叫泰隆7 小时前
MySQL——1、数据库基础
数据库·adb