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 索引,没那么神秘。 📖

相关推荐
苏三说技术9 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎10 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode10 小时前
Redis 在生产项目的使用
前端·后端
用户5598224812210 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode10 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战10 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha10 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn10 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户7623524259111 小时前
ShardingJDBC
后端
行者全栈架构师11 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端