慢 SQL 的本质不是"查得慢",而是"回表次数太多"。
一、什么是回表?为什么回表慢?
InnoDB 索引结构:
js
主键索引:叶子节点 = 完整行数据
二级索引:叶子节点 = 索引列 + 主键值
查询流程
sql
select * from user where age = 18;
存在索引:
diff
index(age)
执行过程:
bash
1. 通过 age 索引定位主键 id
2. 再通过 id 回到主键索引查整行
第 2 步就是:回表
回表为什么慢?
js
二级索引命中 → 1 次 IO
回表主键索引 → 再 1 次 IO
一次查询 = 2 次甚至多次磁盘 IO
二、覆盖索引原理
如果 查询字段全部在索引中,就不需要回表 ------ 这就是覆盖索引。
示例
sql
select id, age from user where age = 18;
索引:
bash
index(age, id)
执行流程:
js
直接在二级索引叶子节点返回结果
无需回表
性能可提升 3 ~ 10 倍
三、回表与覆盖索引执行流程对比
普通索引:
js
二级索引 → 主键索引 → 返回数据
覆盖索引:
js
二级索引 → 直接返回
四、如何判断是否发生回表?
使用 explain:
sql
explain select id, age from user where age=18;
关键字段:
powershell
Extra: Using index
出现 Using index = 覆盖索引(无回表)
五、覆盖索引为什么能快 10 倍?
- IO 次数减少
js
回表 → 2 次 IO
覆盖 → 1 次 IO
- 数据更小
js
索引记录 ≪ 整行数据
- Cache 命中率更高
js
索引页更容易缓存
六、覆盖索引的 3 大核心应用场景
- 列表分页查询
sql
select id, title
from article
where status=1
order by create_time desc
limit 20;
索引:
bash
index(status, create_time, id, title)
完美覆盖 + 无回表
- 统计系统
cs
select count(*) from orders where status=1;
索引:
diff
index(status)
只扫描索引即可
- 用户系统
sql
select id, name from user where phone=?;
索引:
bash
index(phone, id, name)
七、什么时候不适合用覆盖索引?
|---------------|---------|
| 场景 | 原因 |
| select * | 字段太多 |
| 大字段 text/blob | 索引过大 |
| 写频繁 | 索引维护成本高 |
覆盖索引 = 以空间换时间
八、覆盖索引设计黄金法则
markdown
1. 高频查询优先覆盖
2. 列表接口必须覆盖
3. 小字段优先纳入索引
4. 少用 select *
5. 索引字段控制在 5 个以内
九、回表优化 5 大杀招
markdown
1. 覆盖索引
2. 延迟回表
3. 分页游标
4. 只查必要字段
5. 拆表拆字段
十、面试官 6 连问(覆盖索引)
markdown
1. 什么是回表?
2. 回表为什么慢?
3. 覆盖索引是什么?
4. explain 中 Using index 表示什么?
5. 覆盖索引有什么缺点?
6. 什么时候不适合覆盖索引?
十一、终极认知模型
js
是否回表 → IO 次数 → 查询耗时 → 系统吞吐
MySQL 调优的核心:减少回表次数. 回表决定慢 SQL,覆盖索引决定性能上限。
*源码地址*
1、https://pan.baidu.com/s/1B6pgLWfSgMngVeFfSTcPdg?pwd=jc1s
如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!