目录
- 一、什么是覆盖索引?
- 二、使用了覆盖索引 vs 没使用覆盖索引的区别
- 三、例子说明
- 四、总结
🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 线程池 请看: 线程池:从入门到精通,只需一杯咖啡的时间
其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等
如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning
一、什么是覆盖索引?
想象一下,你要查一本很厚的书 📖(数据库表)里的几条信息。
-
普通索引(没覆盖):就像书的目录(索引)。你先在目录里找到你要查的章节 🔍(比如按年龄查人),目录告诉你这个章节在第几页(数据行的位置)。然后,你得翻到那一页 📄(回到主表数据),才能看到完整的章节内容(比如这个人的姓名、邮箱等)。这个“翻到具体页码再去找内容”的动作,就有点像数据库里的“回表” 🏃💨。
-
覆盖索引:还是查书。但这次,你要查的信息(比如姓名和年龄),恰好在那个目录页上就直接写清楚了 ✨!你一看目录,哦,张三,30岁,李四,25岁… 你根本不需要再翻到书的正文页去找了,目录本身就“覆盖”了你所有需要的信息 ✅。
所以,覆盖索引就是一个包含了查询所需所有字段的索引。当数据库发现可以用这个索引直接满足你的查询(包括 SELECT
出来的字段、WHERE
条件里的字段),它就只读取这个索引 🗂️,而不去读取实际的数据行,从而避免了“回表”操作。
二、使用了覆盖索引 vs 没使用覆盖索引的区别
特点 | 没使用覆盖索引 (需要回表 ↪️) | 使用了覆盖索引 (不需要回表 👍) |
---|---|---|
查询过程 | 1. 通过索引找到主键ID。 2. 拿着主键ID去主表里,把完整的数据行捞出来 🏃💨。 3. 从完整数据行里提取你 SELECT 的字段。 | 1. 通过索引找到匹配的行。 2. 索引里已经包含了你 SELECT 的所有字段,直接从索引返回结果 ✅。 |
数据读取 | 需要读取 索引文件 🗂️ + 数据文件 📄 | 只需要读取索引文件 🗂️ |
I/O 操作 | 更多(至少两次磁盘/内存查找) | 更少(一次索引查找) |
性能 | 相对较慢 🐢 | 相对较快 🚀 |
大白话 | 查目录找到页码,再翻到那一页看详细内容。 | 查目录,发现目录上直接就有你要的所有信息,不用翻页了。 |
EXPLAIN | Extra 列没有 Using index | Extra 列会显示 Using index 👀 |
三、例子说明
假设我们有个 users
表 👤:
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),age INT,email VARCHAR(100),INDEX idx_age (age) -- 普通索引,只包含 age 和 主键 id
);
情况一:没使用覆盖索引 🐢
查询:SELECT name, email FROM users WHERE age = 30;
过程:
- MySQL 使用
idx_age
索引,快速找到所有age = 30
的行的主键id
。 - 对于找到的每一个
id
,MySQL 必须回到users
表(聚簇索引)中,根据id
找到完整的数据行 🏃💨。 - 从完整的数据行中提取
name
和email
字段。 - 这里发生了“回表” ↪️,因为
idx_age
索引里只有age
和id
,没有name
和email
。
情况二:使用覆盖索引 🚀
我们创建一个覆盖索引:
-- 先删除旧索引 (如果存在)
-- DROP INDEX idx_age ON users;-- 创建覆盖索引,包含 WHERE 条件列和 SELECT 查询列
CREATE INDEX idx_age_name_email ON users (age, name, email);
查询:SELECT name, email FROM users WHERE age = 30;
过程:
- MySQL 使用
idx_age_name_email
索引。这个索引的叶子节点存储了age
,name
,email
(以及主键id
)。 - 它在索引中找到
age = 30
的条目。 - 因为索引里已经包含了
name
和email
这两个查询需要的字段 ✨,MySQL 直接从索引中读取name
和email
并返回。 - 不需要再根据主键
id
去主表里查找数据了 ✅。避免了“回表”。
四、总结
- 覆盖索引就像一个信息更全的“目录” 📖,让数据库可以直接从目录(索引)里拿到所有需要的数据,不用再费劲去翻正文(主表数据)。
- 主要好处是减少了 I/O 操作(尤其是磁盘 I/O),避免了“回表”,从而显著提高查询性能 🎉。
- 判断是否用上了覆盖索引,最直接的方法是看
EXPLAIN
分析结果的Extra
列是否包含Using index
👀。
当然,创建覆盖索引也有代价 🤔,比如索引会占用更多存储空间 💾,并且在插入、更新、删除数据时,维护索引的成本也会增加。所以需要根据实际的查询场景权衡利弊 ⚖️。