深入理解 MySQL 索引:原理、分类与优化实战

🌈个人主页 :一条泥憨鱼 (欢迎各位大佬莅临)

🎬精选专栏:数据结构与算法JavaSE,苍穹外卖日记

前言:

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

很多初学者第一次接触索引时,会觉得:

  • 概念抽象

  • 原理复杂

  • B+树难懂

  • 优化不会写

但实际上:

索引的本质,就是帮助数据库"快速查找数据"。

你可以把它理解成:

复制代码
书籍的目录

如果一本书没有目录,你想找某一页内容,就只能

复制代码
一页一页翻

但如果有目录,你就能快速定位

MySQL 索引也是同样的道理。

这篇文章将从:

  • 什么是索引

  • 为什么需要索引

  • 索引底层原理

  • B+树结构

  • 索引分类

  • 索引失效

  • SQL优化

等多个角度,带你彻底理解 MySQL 索引。


一、什么是索引?

索引(Index)是数据库中一种:

用于提高查询效率的数据结构。

它的作用:

复制代码
加快数据查询速度

例如:

我们有一张用户表:

java 复制代码
CREATE TABLE user(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(20),
    age INT
);

插入10万条数据后:

如果执行:

java 复制代码
SELECT * FROM user WHERE name='张三';

MySQL 会:

复制代码
从第一条开始
一条一条找

这种方式叫:

复制代码
全表扫描

效率非常低。

如果给 name 字段添加索引

java 复制代码
CREATE INDEX idx_name ON user(name);

数据库就能快速定位数据,查询速度会大幅提升。


二、为什么索引能提高查询速度?

核心原因:

复制代码
减少数据扫描次数

没有索引:

复制代码
100万条数据
可能扫描100万次

有索引:

复制代码
可能只需要扫描几次

这就像:


没有目录的书

你想找:

复制代码
第500页内容

只能:

复制代码
从第一页翻到500页

有目录的书

直接:

复制代码
目录 → 第500页

效率差距巨大。


三、索引的底层数据结构

很多面试中都会问:

MySQL索引底层是什么?

答案:

复制代码
B+Tree(B+树)

四、为什么不用数组或链表?


4.1 数组的问题

数组查找快:

复制代码
支持下标随机访问

但是插入数据很慢。

例如:

复制代码
1 2 4 5

插入3:

复制代码
1 2 3 4 5

后面元素都要移动。

数据库频繁增删改,数组不适合。


4.2 链表的问题

链表插入快,但查询慢。

因为:

复制代码
只能一个一个找

不适合数据库查询。


4.3 二叉树的问题

普通二叉树:

可能退化成链表。

例如:

复制代码
1
 \
  2
   \
    3
     \
      4

查询效率很差。


五、B+树是什么?

MySQL 最常用的索引结构:

复制代码
B+Tree

它是一种:

复制代码
多路平衡搜索树

特点:

  • 查询快

  • 层级少

  • 磁盘IO少

  • 非常适合数据库


六、B+树结构特点


6.1 所有数据都在叶子节点

B+树中:

真正的数据:

复制代码
只存储在叶子节点

非叶子节点只存索引。


6.2 叶子节点形成链表

叶子节点之间,会形成双向链表

因此:

复制代码
范围查询效率极高

例如:

java 复制代码
SELECT * FROM user WHERE id BETWEEN 100 AND 200;

6.3 树高度低

B+树的一个节点能存很多数据。

因此:

复制代码
树层级很少

通常:

复制代码
3~4层

就能存千万级数据。


七、聚簇索引与非聚簇索引

这是 MySQL 高频面试题。


7.1 聚簇索引(Clustered Index)

InnoDB 中,主键索引就是聚簇索引

特点:

复制代码
数据和索引放在一起

例如:

复制代码
PRIMARY KEY(id)

叶子节点,直接存整行数据。


7.2 非聚簇索引(二级索引)

普通索引:

复制代码
CREATE INDEX idx_name ON user(name);

叶子节点存的是:

复制代码
主键值

查询时,还要回到主键索引查数据。

这个过程叫:

复制代码
回表查询

八、索引分类


8.1 主键索引

创建主键时自动生成。

java 复制代码
CREATE TABLE student(
    id INT PRIMARY KEY,
    name VARCHAR(20)
);

特点:

  • 唯一

  • 不能为空


8.2 唯一索引

保证字段唯一。

java 复制代码
CREATE UNIQUE INDEX idx_phone
ON user(phone);

例如:

手机号不能重复。


8.3 普通索引

最常见。

java 复制代码
CREATE INDEX idx_age
ON user(age);

仅用于提高查询效率。


8.4 联合索引(复合索引)

多个字段共同组成。

java 复制代码
CREATE INDEX idx_name_age
ON user(name,age);

适用于:

java 复制代码
WHERE name=? AND age=?

8.5 全文索引

用于:

复制代码
文本搜索

例如:

复制代码
FULLTEXT(content)

九、创建索引


9.1 创建普通索引

java 复制代码
CREATE INDEX idx_name
ON user(name);

9.2 创建唯一索引

java 复制代码
CREATE UNIQUE INDEX idx_email
ON user(email);

9.3 创建联合索引

java 复制代码
CREATE INDEX idx_name_age
ON user(name,age);

9.4 删除索引

java 复制代码
DROP INDEX idx_name ON user;

十、查看SQL是否使用索引

使用:

java 复制代码
EXPLAIN

例如:

java 复制代码
EXPLAIN
SELECT * FROM user WHERE name='张三';

十一、EXPLAIN重要字段


11.1 type

SQL性能指标。

常见:

type 性能
all 全表扫描(最差)
index 扫描索引
range 范围查询
ref 普通索引查询
const 主键查询(最好)

11.2 key

使用了哪个索引。


11.3 rows

扫描行数越少越好。


十二、索引失效场景

很多时候,明明建了索引,但SQL还是很慢。

原因:

复制代码
索引失效

12.1 对索引列使用函数

错误示例:

复制代码
SELECT * FROM user
WHERE YEAR(create_time)=2025;

索引失效。

正确:

复制代码
SELECT * FROM user
WHERE create_time BETWEEN
'2025-01-01'
AND '2025-12-31';

12.2 模糊查询以%开头

错误:

复制代码
LIKE '%abc'

索引失效。

正确:

复制代码
LIKE 'abc%'

12.3 字段类型不一致

例如:

复制代码
name VARCHAR

但:

复制代码
WHERE name=123

可能导致隐式转换,索引失效。


12.4 使用or

例如:

复制代码
WHERE age=18 OR salary=5000

可能索引失效。


12.5 联合索引不满足最左前缀

例如:

复制代码
(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_age
ON user(name,age);

SQL:

复制代码
SELECT name,age
FROM user
WHERE name='张三';

由于:

复制代码
name age 都在索引中

因此:

复制代码
无需回表

性能更高。


十五、索引不是越多越好

很多初学者认为索引越多越快,其实这是不对的。


15.1 索引占空间

索引需要额外存储。


15.2 更新会变慢

执行:

复制代码
INSERT
UPDATE
DELETE

索引也要维护。并且索引越多,维护成本越高。


十六、索引优化建议


16.1 高频查询字段建索引

例如:

复制代码
用户名
手机号
订单号

16.2 数据量小不需要索引

例如:

复制代码
几十条数据

全表扫描更快。


16.3 区分度高的字段适合索引

例如:

复制代码
手机号
身份证号

不适合:

复制代码
性别

因为:

复制代码
重复值太多

16.4 联合索引优于多个单列索引

推荐:

复制代码
(name,age)

而不是:

复制代码
name
age

16.5 尽量使用覆盖索引

减少回表。


十七、JavaWeb中的索引优化场景


17.1 登录功能

java 复制代码
SELECT * FROM user
WHERE username=?;

username 应加索引。


17.2 商品搜索

java 复制代码
SELECT * FROM product
WHERE category_id=?;

商品分类应加索引。


17.3 订单查询

java 复制代码
SELECT * FROM orders
WHERE user_id=?
ORDER BY create_time DESC;

推荐联合索引:

复制代码
(user_id,create_time)

十八、面试高频问题


18.1 为什么索引能提高查询效率?

因为减少了数据扫描次数。


18.2 MySQL索引底层是什么?

复制代码
B+Tree

18.3 聚簇索引和非聚簇索引区别?

聚簇索引:

复制代码
数据和索引在一起

非聚簇索引:

复制代码
索引存主键值
需要回表

18.4 什么是回表查询?

先查普通索引:

再查主键索引。


18.5 什么是最左前缀原则?

联合索引必须从最左边字段开始使用。


十九、总结

索引是 MySQL 性能优化的核心。

它的本质:

复制代码
帮助数据库快速查找数据

重点一定要掌握:

  • B+树

  • 聚簇索引

  • 联合索引

  • 最左前缀

  • 覆盖索引

  • 索引失效

对于开发者来说,真正的高性能系统:

并不是:

复制代码
代码写得多复杂

而是:

复制代码
SQL是否高效
索引是否合理

数据库性能,往往决定整个系统的性能上限。

相关推荐
windawdaysss1 小时前
离线学习SQL和数据库的工具及其部署
数据库·sql·学习
Rubin智造社1 小时前
Claude Code开发者大会系列8:从脚本到智能体——独立开发者的“AI原生”工作流转型
数据库·人工智能·独立开发者·agentic工作流·ai原生开发·实操指南
楠枬1 小时前
Redis 缓存
数据库·redis·缓存
一条泥憨鱼1 小时前
详解MySQL事务(超详细版)
java·数据库·mysql·spring·maven·后端开发
j7~1 小时前
【MYSQL】 数据库的常见数据类型--详解
数据库·mysql·decimal·varchar·数据库的基本类型
rising start10 小时前
二、全面理解MySQL架构
mysql·架构
星星也在雾里11 小时前
PgBouncer 解决 PostgreSQL 连接数超限 + 可视化监控
数据库·postgresql
bqq1986102611 小时前
MySQL性能优化
mysql·mysql优化
雨辰AI12 小时前
SpringBoot3 + 人大金仓读写分离 + 分库分表 + 集群高可用 全栈实战
java·数据库·mysql·政务