MySQL 索引到底是什么?普通人也能看懂的通俗讲解

MySQL 索引到底是什么?普通人也能看懂的通俗讲解


一、先从一个生活场景说起

想象一下,你是一家图书馆的管理员,图书馆里有 100万本书 ,但没有任何分类,全部堆在一个大仓库里。

有一天,读者跑来问你:

"请帮我找一本叫《活着》的书。"

你怎么办?只能从第一本开始,一本一本翻,运气好第50本找到,运气不好翻到第99万本。

读者等得不耐烦了,骂你:

"找一本书要半天,这图书馆还开什么开!"


这时候,你做了一件事------做了一个"索引"

你花了一天时间,把所有书名按拼音首字母排序,写在一个本子上:

css 复制代码
A  → 第3排第5个书架
B  → 第7排第2个书架
...
H  → 第12排第8个书架   ←《活着》在这里!
...
Z  → 第20排第1个书架

下次再有人找《活着》,你不用翻书了,直接查本子:

H → 第12排第8个书架 → 走过去 → 拿到书。

30秒搞定。


这个"本子",就是 MySQL 的索引

把上面的场景翻译成技术语言:

生活场景 MySQL 术语
100万本书 数据表中的100万行数据
一本一本翻 全表扫描(Full Table Scan)
那个排序的本子 索引(Index)
按拼音首字母排序 B+Tree 索引结构
查本子再找书 索引查找 + 回表

一句话总结:索引就是一个"排好序的快速查找目录",帮你不用全表扫描就能找到数据。


二、没有索引 vs 有索引,差距有多大?

假设有一张用户表 user,有 1000万条记录 ,你要找 id = 9999999 的那个人:

❌ 没有索引

erlang 复制代码
MySQL 的执行过程:
第1行 → 不是
第2行 → 不是
第3行 → 不是
...
第9999999行 → 是!找到了!

扫描了 9999999行 ,耗时可能 几秒钟甚至十几秒

✅ 有索引(id 为主键,自带索引)

css 复制代码
MySQL 的执行过程:
查 B+Tree → 走3层就定位到了 → 直接找到那一行

只查了 3次 ,耗时 0.001秒不到

1000万行数据,差距是 几万倍。


三、索引到底长什么样?(B+Tree 通俗版)

MySQL 最常用的索引结构叫 B+Tree,别被名字吓到,它其实就是一棵"多叉查找树"。

想象你在玩一个猜数字游戏

我心里想了1~1000之间的一个数,你来猜。

笨办法(全表扫描)

1?不是。2?不是。3?不是......

聪明办法(二分查找)

500?大了。250?小了。375?大了。312?小了......

B+Tree 就是这个思路的升级版 ,只不过它不是"二分"(每次分2份),而是 "多分" (每次分几百份)。

css 复制代码
                    [500 | 1000 | 1500]
                   /      |       \
          [100|300]  [600|800]  [1200|1400]
          /   |  \   /  |  \   /   |   \
       1-99 101-299 ...          ...  1401-1999
       ↑
   叶子节点存的才是真实数据(或者数据的地址)

关键特点

  • 树的高度很低(1000万数据,通常只有 3~4层
  • 每一层都排好序,查找时不用遍历,直接跳
  • 最底层的叶子节点之间有链表相连,方便范围查询

比喻:就像你查字典,不是从第一页翻,而是先翻到"H"开头的部分,再翻到"huo"的部分,几下就到了。


四、索引不是银弹------它也有代价

很多新手觉得"那我把所有字段都加上索引不就完了?"

不行。索引是有代价的

代价1:占空间

那个"本子"本身也要地方放。一张表的索引,可能比数据本身还大。

代价2:写操作变慢

你每次新增/修改/删除 一本书,不光要放书,还要更新那个本子

markdown 复制代码
INSERT 一条数据:
  - 要把数据写入表 ✅
  - 要把索引也插入 B+Tree ✅  ← 多了这一步!
  
UPDATE 一个字段:
  - 如果这个字段有索引,还要去修改索引树 ✅ ← 又多了一步!
  
DELETE 一条数据:
  - 删除数据 ✅
  - 删除索引中的记录 ✅ ← 还是多了一步!

比喻:图书馆每进一本新书,你都要在本子上插入一行,还得保持排序。书越多,你越忙。

代价3:索引太多,优化器会"懵"

MySQL 优化器要从多个索引中选一个最优的,索引太多反而让它选错。


五、索引的常见类型(用人话说)

索引类型 通俗比喻 适用场景
主键索引(PRIMARY) 身份证号,每个人唯一,自动建索引 每个表都该有
普通索引(INDEX) 书本的拼音目录 经常用来查询的字段,如 email
唯一索引(UNIQUE) 身份证号目录,不允许重复 usernamephone
联合索引(Composite) 先按"姓氏"排,姓氏相同再按"名字"排 WHERE last_name='张' AND first_name='三'
全文索引(FULLTEXT) 书的内容关键词检索 文章内容搜索

六、联合索引------最容易踩坑的地方

这是面试和实战中最高频的考点,用生活例子讲清楚。

假设你建了一个联合索引:(姓, 名)

markdown 复制代码
相当于电话簿:先按姓氏排序,同姓的再按名字排序。

张三 → 张三丰
     → 张三李四(不是,姓张名三李四?不对,应该是张姓,三李四是名)
     → 张伟
     
李四 → 李四光
     → 李四

✅ 能用上索引的查询

sql 复制代码
sql
WHERE 姓 = '张'                    -- 用上了!先找姓张的
WHERE 姓 = '张' AND 名 = '三'       -- 用上了!精确定位

❌ 用不上索引的查询

sql 复制代码
sql
WHERE 名 = '三' 没用!只知道名,不知道姓,相当于让你在电话簿里找所有名字叫"三"的人,你得翻整本!
WHERE 名 = '三' AND 姓 = '张'       -- 注意!顺序反了也用不上!MySQL只认从左到右

🎯 最重要的一句话:联合索引遵循"最左前缀原则",从左往右匹配,断了就废了。

比喻:你按"省-市-区"建了索引,查询"浙江省杭州市"能用上,但直接查"杭州市"就用不上------因为你不知道是哪个省的杭州。


七、什么时候该建索引?什么时候不该建?

✅ 该建索引的情况

  • 字段经常出现在 WHERE 后面
  • 字段经常用于 JOIN 关联
  • 字段经常用于 ORDER BY 排序
  • 字段经常用于 GROUP BY 分组

❌ 不该建索引的情况

  • 数据量很少的表(几百行,全表扫描更快)
  • 经常被更新的字段(写代价太大)
  • 区分度很低的字段(如"性别":男/女,建了索引也没啥用,因为一半数据都符合)

"性别"这种字段,索引查找后还要回表扫描一半的数据,还不如直接全表扫描快。


八、怎么看你的索引有没有生效?

EXPLAIN 命令,这是 MySQL 给你的"体检报告":

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

输出结果关注这几列:

列名 你该看什么 理想值
type 访问类型 refrangeconst(越左越好)
key 实际用了哪个索引 有值就好,NULL = 没用上索引
rows 预估扫描行数 越少越好
Extra 额外信息 出现 Using index 最好(覆盖索引,不用回表)

最怕看到的

ini 复制代码
type = ALL  → 全表扫描,完蛋
key = NULL  → 没用索引,完蛋
rows = 1000000 → 扫描100万行,完蛋

九、一张图总结全文

vbnet 复制代码
┌─────────────────────────────────────────┐
│            MySQL 索引 一张图看懂          │
├─────────────────────────────────────────┤
│                                         │
│  是什么?  → 排好序的查找目录(像字典)    │
│                                         │
│  为什么快? → B+Tree,3~4层找到数据       │
│             全表扫描要几百万次              │
│                                         │
│  代价?   → 占空间 + 写变慢               │
│                                         │
│  怎么建?  → WHERE/JOIN/ORDER/GROUP的字段 │
│             别建在性别这种低区分度字段上     │
│                                         │
│  联合索引? → 最左前缀原则,断了就废       │
│             像电话簿:先姓后名              │
│                                         │
│  怎么检查? → EXPLAIN 看 type 和 key      │
│                                         │
└─────────────────────────────────────────┘

十、最后一句话

索引的本质就是"空间换时间"------你多花点空间存一个目录,换来查询速度提升几千倍。但目录也不是越多越好,建对了是神器,建错了是负担。

就像图书馆那个本子------该建的建,不该建的别建,建了就要维护好。

这就是 MySQL 索引,没那么神秘。 📖

相关推荐
阿苟1 小时前
spring重点详解
java·后端·面试
l软件定制开发工作室2 小时前
Spring开发系列教程(35)——使用Actuator
java·后端·spring
我叫黑大帅3 小时前
PyScript-GitHubRepo: 构建高性能GitHub仓库批量下载工具的技术实践
后端·python·面试
平凡但不平庸的码农3 小时前
Go 错误处理详解
开发语言·后端·golang
请你喝可乐5 小时前
AI Agent Skill 高阶使用指南:从入门到精通
后端
用户962377954485 小时前
代码审计 | Struts2 —— S2-016 OGNL 注入原理
后端
9号达人5 小时前
为什么你应该在 MQ 里用多个消费者,而不是一个
java·后端·架构
阿星做前端5 小时前
重度 AI 编程用户的一天:我怎么把 Claude Code / Codex 工作流搬进浏览器工作台
前端·javascript·后端
代码羊羊5 小时前
Rust 类型转换全方位通俗易懂指南(as、TryInto、强制转换、Transmute)
后端·rust