MySQL的覆盖索引是什么?
重要内容
覆盖索引的核心在于索引包含查询所需的所有字段(WHERE、SELECT、ORDER BY、GROUP BY等子句中的列),使得查询无需访问数据行(即不需要回表),仅通过索引即可完成数据获取
扩展知识
覆盖索引的工作原理
常规查询流程(无覆盖索引)
- 通过二级索引定位到主键值
- 根据主键值回表查询聚簇索引获取完整数据行
- 这一过程涉及两次B+树查找(二级索引 → 主键索引 → 数据行),产生额外I/O开销
覆盖索引流程
- 查询所需的字段直接存储在二级索引中
- 仅需遍历二级索引的B+树,直接返回索引中的值,无需回表
覆盖索引的优点
优势类型 | 具体表现 |
---|---|
减少I/O操作 | 索引条目通常远小于数据行,直接读取索引减少磁盘访问次数 |
避免主键回表 | InnoDB二级索引包含主键值,覆盖查询可跳过聚簇索引的二次查询 |
减少锁竞争 | 仅访问索引而非数据行,降低行锁冲突概率 |
加速排序/分组 | 若索引包含ORDER BY或GROUP BY字段,可直接利用索引顺序,避免临时表 |
演示覆盖索引示例
首先创建一个简单的 employees
表,包含员工的 id
、name
、age
和 department
信息
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;
-- 创建 employees 表
CREATE TABLE employees (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
age INT,
department VARCHAR(50)
);
-- 插入示例数据
INSERT INTO employees (name, age, department) VALUES
('Alice', 25, 'HR'),
('Bob', 30, 'IT'),
('Charlie', 35, 'Finance');
使用覆盖索引
- 创建复合索引
为了让查询能够使用覆盖索引,我们创建一个包含 name
和 age
字段的复合索引
sql
-- 创建复合索引
CREATE INDEX idx_name_age ON employees (name, age);
- 执行使用覆盖索引的查询
下面的查询只需要从索引中获取 name
和 age
字段的值,而不需要回表查询
sql
-- 使用覆盖索引的查询
EXPLAIN SELECT name, age FROM employees WHERE name = 'Alice';
在 EXPLAIN
结果中,Extra
列会显示 Using index
,这表示查询使用了覆盖索引
未使用覆盖索引
- 查询需要回表的情况
如果查询中包含了不在索引中的字段,就需要回表查询
sql
-- 未使用覆盖索引的查询
EXPLAIN SELECT name, age, department FROM employees WHERE name = 'Alice';
在这个查询中,由于 department
字段不在 idx_name_age
索引中,所以查询需要根据索引定位到记录的主键,然后再回表查询 department
字段的值。在 EXPLAIN
结果中,Extra
列通常不会显示 Using index