深入理解 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是否高效
索引是否合理

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

相关推荐
一嘴一个橘子5 分钟前
MySqL 的 B+树、 叶子节点、非叶子节点
mysql
麦聪聊数据10 分钟前
企业数据市场建设(三):API 化服务封装,让数据开箱即用、避免重复开发
数据库
麦聪聊数据22 分钟前
企业数据市场建设(四):流程闭环与价值运营,让数据市场真正转起来
运维·数据库
正儿八经的少年29 分钟前
redis 的大 key 和热 key 详解
数据库·redis·缓存
AI砖家32 分钟前
多智能体系统实战:架构设计、数据库表设计与 Skill 体系
数据库·多智能体·skill·agent架构设计·agengt
夜雪一千1 小时前
MySQL查询条件的顺序是否影响查询效率
数据库·mysql
X-⃢_⃢-X1 小时前
十、Redis之布隆过滤器
数据库·redis·缓存
Nturmoils1 小时前
订单号查出了三笔,我以为是数据脏了,其实是自己写错了
数据库
ZKNOW甄知科技1 小时前
燕千云深度集成飞书:以AI之力,开启无感IT运维体验
大数据·运维·网络·数据库·人工智能·低代码·集成学习
WWJA王文举1 小时前
单片机参数如何掉电保存:Flash、EEPROM和配置存储完整设计
数据库·stm32·mongodb·c#