在学习 MySQL 的过程中,“索引(Index)”一定是最核心、最重要的知识之一。

很多初学者第一次接触索引时,会觉得:
概念抽象
原理复杂
B+树难懂
优化不会写
但实际上:
索引的本质,就是帮助数据库“快速查找数据”。
你可以把它理解成:
书籍的目录
如果一本书没有目录,你想找某一页内容,就只能
一页一页翻
但如果有目录,你就能快速定位。
MySQL 索引也是同样的道理。
这篇文章将从:
什么是索引
为什么需要索引
索引底层原理
B+树结构
索引分类
索引失效
SQL优化
等多个角度,带你彻底理解 MySQL 索引。
索引(Index)是数据库中一种:
用于提高查询效率的数据结构。
它的作用:
加快数据查询速度
例如:
我们有一张用户表:
CREATE TABLE user( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), age INT);
插入10万条数据后:
如果执行:
SELECT * FROM user WHERE name='张三';
MySQL 会:
从第一条开始一条一条找
这种方式叫:
全表扫描
效率非常低。
如果给 name 字段添加索引
CREATE INDEX idx_name ON user(name);
数据库就能快速定位数据,查询速度会大幅提升。
核心原因:
减少数据扫描次数
没有索引:
100万条数据可能扫描100万次
有索引:
可能只需要扫描几次
这就像:
你想找:
第500页内容
只能:
从第一页翻到500页
直接:
目录 → 第500页
效率差距巨大。
很多面试中都会问:
MySQL索引底层是什么?
答案:
B+Tree(B+树)
数组查找快:
支持下标随机访问
但是插入数据很慢。
例如:
1 2 4 5
插入3:
1 2 3 4 5
后面元素都要移动。
数据库频繁增删改,数组不适合。
链表插入快,但查询慢。
因为:
只能一个一个找
不适合数据库查询。
普通二叉树:
可能退化成链表。
例如:
1 2 3 4
查询效率很差。
MySQL 最常用的索引结构:
B+Tree
它是一种:
多路平衡搜索树
特点:
查询快
层级少
磁盘IO少
非常适合数据库
B+树中:
真正的数据:
只存储在叶子节点
非叶子节点只存索引。
叶子节点之间,会形成双向链表。
因此:
范围查询效率极高
例如:
SELECT * FROM user WHERE id BETWEEN 100 AND 200;
B+树的一个节点能存很多数据。
因此:
树层级很少
通常:
3~4层
就能存千万级数据。
这是 MySQL 高频面试题。
InnoDB 中,主键索引就是聚簇索引。
特点:
数据和索引放在一起
例如:
PRIMARY KEY(id)
叶子节点,直接存整行数据。
普通索引:
CREATE INDEX idx_name ON user(name);
叶子节点存的是:
主键值
查询时,还要回到主键索引查数据。
这个过程叫:
回表查询
创建主键时自动生成。
CREATE TABLE student( id INT PRIMARY KEY, name VARCHAR(20));
特点:
唯一
不能为空
保证字段唯一。
CREATE UNIQUE INDEX idx_phoneON user(phone);
例如:
手机号不能重复。
最常见。
CREATE INDEX idx_ageON user(age);
仅用于提高查询效率。
多个字段共同组成。
CREATE INDEX idx_name_ageON user(name,age);
适用于:
WHERE name=? AND age=?
用于:
文本搜索
例如:
FULLTEXT(content)
CREATE INDEX idx_nameON user(name);
CREATE UNIQUE INDEX idx_emailON user(email);
CREATE INDEX idx_name_ageON user(name,age);
DROP INDEX idx_name ON user;
使用:
EXPLAIN
例如:
EXPLAINSELECT * FROM user WHERE name='张三';
SQL性能指标。
常见:
| type | 性能 |
|---|---|
| all | 全表扫描(最差) |
| index | 扫描索引 |
| range | 范围查询 |
| ref | 普通索引查询 |
| const | 主键查询(最好) |
使用了哪个索引。
扫描行数越少越好。
很多时候,明明建了索引,但SQL还是很慢。
原因:
索引失效
错误示例:
SELECT * FROM userWHERE YEAR(create_time)=2025;
索引失效。
正确:
SELECT * FROM userWHERE create_time BETWEEN'2025-01-01'AND '2025-12-31';
错误:
LIKE '%abc'
索引失效。
正确:
LIKE 'abc%'
例如:
name VARCHAR
但:
WHERE name=123
可能导致隐式转换,索引失效。
例如:
WHERE age=18 OR salary=5000
可能索引失效。
例如:
(name,age,gender)
SQL:
WHERE age=20
无法使用联合索引。
因为:
没有从最左边开始
联合索引最重要的规则。
例如:
(name,age,gender)
可以使用:
WHERE name=?WHERE name=? AND age=?WHERE name=? AND age=? AND gender=?
不能直接:
WHERE age=?
什么是覆盖索引?
即:
查询的数据刚好都在索引中
不需要回表。
例如:
CREATE INDEX idx_name_ageON user(name,age);
SQL:
SELECT name,ageFROM userWHERE name='张三';
由于:
name age 都在索引中
因此:
无需回表
性能更高。
很多初学者认为索引越多越快,其实这是不对的。
索引需要额外存储。
执行:
INSERTUPDATEDELETE
索引也要维护。并且索引越多,维护成本越高。
例如:
用户名手机号订单号
例如:
几十条数据
全表扫描更快。
例如:
手机号身份证号
不适合:
性别
因为:
重复值太多
推荐:
(name,age)
而不是:
nameage
减少回表。
SELECT * FROM userWHERE username=?;
username 应加索引。
SELECT * FROM productWHERE category_id=?;
商品分类应加索引。
SELECT * FROM ordersWHERE user_id=?ORDER BY create_time DESC;
推荐联合索引:
(user_id,create_time)
因为减少了数据扫描次数。
B+Tree
聚簇索引:
数据和索引在一起
非聚簇索引:
索引存主键值需要回表
先查普通索引:
再查主键索引。
联合索引必须从最左边字段开始使用。
索引是 MySQL 性能优化的核心。
它的本质:
帮助数据库快速查找数据
重点一定要掌握:
B+树
聚簇索引
联合索引
最左前缀
覆盖索引
索引失效
对于开发者来说,真正的高性能系统:
并不是:
代码写得多复杂
而是:
SQL是否高效索引是否合理
数据库性能,往往决定整个系统的性能上限。