每日一Go·MySQL-14、慢 SQL 产生原因全解

慢 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:索引失效

  1. 隐式类型转换
apache 复制代码
where phone = 13800138000;
#phone = varchar → 索引失效
  1. 函数计算
apache 复制代码
where date(create_time) = '2025-01-01';
#索引失效
  1. like 以 % 开头
bash 复制代码
where name like '%张';
#索引失效
  1. 范围后字段失效
bash 复制代码
(a,b,c)
where a=? and b>? and c=?
#c失效

五、原因 3:索引设计错误

  1. 单列索引滥用
bash 复制代码
idx_a
idx_b
idx_c
where a=? and b=? and c>?
#MySQL 只能真正用一个索引
  1. 联合索引顺序错误
bash 复制代码
index(create_time, user_id)
where user_id=? and create_time>?
#user_id 无法有效利用
  1. 索引过多

|----|-------|-------|
| 写慢 | 维护成本高 | 页分裂频繁 |

六、原因 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:排序 / 分组 / 分页不合理

  1. filesort 排序
apache 复制代码
order by create_time desc;
#无索引:-》 CPU + IO 双杀
  1. group by 使用临时表
powershell 复制代码
group by user_id;
#Extra:
Using temporary
-》 内存 / 磁盘临时表
  1. 深分页
bash 复制代码
limit 500000,20;
-〉系统性灾难

九、原因 7:锁等待 & 并发冲突

  1. 行锁等待
sql 复制代码
update / delete 未提交
select ... for update;
-〉被阻塞
  1. 表锁冲突
diff 复制代码
DDL + 大事务
-〉全表阻塞
  1. 热点更新
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. 场景 1:排行榜查询崩溃
sql 复制代码
select * from score 
order by score desc 
limit 100000,20;

问题:深分页 + filesort

解决:

sql 复制代码
where score < last_score 
order by score desc 
limit 20;
  1. 场景 2:统计接口雪崩
cs 复制代码
select count(*) from orders;

解决:

  • 预聚合表

  • Redis 计数缓存

  1. 场景 3:活动库存卡死
bash 复制代码
update stock set num=num-1 where id=1;

问题:热点行锁

解决:

  • 业务拆分

  • 批量扣减

  • Redis + 异步落库

十三、慢 SQL 调优终极思维模型

nginx 复制代码
SQL → 索引 → 执行路径 → IO → 锁 → 性能

优化顺序:

sql 复制代码
索引 → SQL 改写 → 架构拆分 → 缓存 → 异步化

十四、面试官 10 连杀

    1. 慢 SQL 产生原因有哪些?
    1. explain 里最关键字段?
    1. filesort 是什么?
    1. 如何定位线上慢 SQL?
    1. 深分页怎么解决?
    1. 回表是什么?
    1. 如何减少锁等待?
    1. 如何分析死锁?
    1. 慢日志如何配置?
    1. 优化 SQL 的通用套路?

十五、一句话总结

慢 SQL 的本质:不是查得慢,而是扫描多、IO 多、锁等待多。



*源码地址*

这里不能发


如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!

相关推荐
新*15 小时前
Elasticsearch 7.17 的 SQL 到底能查到什么?一次踩坑记录
后端·sql·elasticsearch·查询
星恒随风19 小时前
MySQL 从零入门(四):表的增删改查与基础查询详解
linux·服务器·数据库·笔记·mysql
Pniubi21 小时前
MySQL靠什么实现事务的?事务隔离级别有哪些?
java·数据库·mysql
aiks_yuan21 小时前
MySQL 死锁怎么排查:看懂 INNODB STATUS 死锁日志,先查后插为什么必死锁(MySQL 8.2 实测)
mysql
进击的荆棘1 天前
MySQL——库的操作
数据库·mysql
计算机毕设定制辅导-无忧学长1 天前
《基于Spring Boot的迷游哈游戏综合服务平台的开发》
java·vue.js·spring boot·mysql·迷游哈游戏综合服务平台
这个DBA有点耶2 天前
库内计算推理:一条SQL背后的算子融合,和外挂方案差了几次网络往返
数据库·人工智能·sql
这个DBA有点耶2 天前
函数索引的“完全一致”有多苛刻:写法、字符集、类型,差一处就失效
数据库·mysql·代码规范
星恒随风2 天前
MySQL 从零入门(三):表的约束详解
linux·服务器·数据库·笔记·mysql