慢 SQL 从来不是"偶然",而是系统设计、索引结构、执行路径共同作用的必然结果。
一、慢 SQL 本质公式
nginx
SQL 耗时 ≈ 扫描行数 × 单行处理成本 × 磁盘 IO 次数
你只需要盯死这三点:
js
扫描行数 | IO 次数 | 回表次数
二、慢 SQL 的 7 大根本原因
markdown
1. 索引缺失
2. 索引失效
3. 索引设计错误
4. 扫描行数过多
5. 回表次数过多
6. 排序 / 分组 / 分页不合理
7. 锁等待 & 并发冲突
三、原因 1:索引缺失
apache
select * from orders where user_id = 123;
#user_id 没有索引 → 全表扫描
#EXPLAIN:
type: ALL
rows: 1000000
四、原因 2:索引失效
- 隐式类型转换
apache
where phone = 13800138000;
#phone = varchar → 索引失效
- 函数计算
apache
where date(create_time) = '2025-01-01';
#索引失效
- like 以 % 开头
bash
where name like '%张';
#索引失效
- 范围后字段失效
bash
(a,b,c)
where a=? and b>? and c=?
#c失效
五、原因 3:索引设计错误
- 单列索引滥用
bash
idx_a
idx_b
idx_c
where a=? and b=? and c>?
#MySQL 只能真正用一个索引
- 联合索引顺序错误
bash
index(create_time, user_id)
where user_id=? and create_time>?
#user_id 无法有效利用
- 索引过多
|----|-------|-------|
| 写慢 | 维护成本高 | 页分裂频繁 |
六、原因 4:扫描行数过多
深分页:
cs
#扫描100020 行
select * from orders limit 100000, 20;
#模糊搜索:-》全表扫描
where content like '%mysql%';
#统计类 SQL: 亿级数据 → 全表扫描
select count(*) from orders;
七、原因 5:回表次数过多
普通索引:
cs
select * from user where age=18;
#流程
二级索引 → 主键 → 回表
-》 2 倍 IO
八、原因 6:排序 / 分组 / 分页不合理
- filesort 排序
apache
order by create_time desc;
#无索引:-》 CPU + IO 双杀
- group by 使用临时表
powershell
group by user_id;
#Extra:
Using temporary
-》 内存 / 磁盘临时表
- 深分页
bash
limit 500000,20;
-〉系统性灾难
九、原因 7:锁等待 & 并发冲突
- 行锁等待
sql
update / delete 未提交
select ... for update;
-〉被阻塞
- 表锁冲突
diff
DDL + 大事务
-〉全表阻塞
- 热点更新
diff
库存表 / 账户表
-〉行锁竞争激烈
十、慢 SQL 线上排查 7 步法
markdown
1. 开启慢日志
2. 定位 SQL
3. explain 分析
4. 找索引问题
5. 判断回表 & filesort
6. 评估锁等待
7. 验证优化效果
十一、慢 SQL 定位工具矩阵
|--------------------|---------|
| 工具 | 作用 |
| slow_query_log | 定位慢 SQL |
| explain | 执行计划 |
| performance_schema | 锁等待分析 |
| show processlist | 阻塞排查 |
| pt-query-digest | 慢日志分析 |
十二、经典慢 SQL 场景复盘
- 场景 1:排行榜查询崩溃
sql
select * from score
order by score desc
limit 100000,20;
问题:深分页 + filesort
解决:
sql
where score < last_score
order by score desc
limit 20;
- 场景 2:统计接口雪崩
cs
select count(*) from orders;
解决:
-
预聚合表
-
Redis 计数缓存
- 场景 3:活动库存卡死
bash
update stock set num=num-1 where id=1;
问题:热点行锁
解决:
-
业务拆分
-
批量扣减
-
Redis + 异步落库
十三、慢 SQL 调优终极思维模型
nginx
SQL → 索引 → 执行路径 → IO → 锁 → 性能
优化顺序:
sql
索引 → SQL 改写 → 架构拆分 → 缓存 → 异步化
十四、面试官 10 连杀
-
- 慢 SQL 产生原因有哪些?
-
- explain 里最关键字段?
-
- filesort 是什么?
-
- 如何定位线上慢 SQL?
-
- 深分页怎么解决?
-
- 回表是什么?
-
- 如何减少锁等待?
-
- 如何分析死锁?
-
- 慢日志如何配置?
-
- 优化 SQL 的通用套路?
十五、一句话总结
慢 SQL 的本质:不是查得慢,而是扫描多、IO 多、锁等待多。
*源码地址*
这里不能发
如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!