文章目录
开篇暴击:为什么你的SQL总是跑得慢?
最近在帮朋友公司排查生产环境性能问题,发现一个典型现象:80%的慢查询都是因为开发人员没掌握基础优化技巧!!!(特别是三年以下经验的程序员)今天我们就用真实案例,手把手教你如何驯服那些磨人的慢SQL。
实战案例背景
某电商平台订单查询接口频繁超时,原始SQL执行需要20秒+,优化后稳定在0.2秒以内。以下是完整优化过程:
原始慢SQL(已脱敏):
SELECT o.order_id, u.username, p.product_name
FROM orders o
LEFT JOIN users u ON o.user_id = u.user_id
LEFT JOIN products p ON o.product_id = p.product_id
WHERE o.create_time BETWEEN '2023-01-01' AND '2023-12-31'
AND o.status IN (1,3,5)
ORDER BY o.order_amount DESC
LIMIT 1000;
优化七步杀(亲测有效)
第一步:定位罪魁祸首
-- 开启慢查询日志(重要!!!)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2; -- 超过2秒的查询记录
第二天检查日志发现:
# Query_time: 23.123456 Lock_time: 0.123456 Rows_sent: 1000 Rows_examined: 1587923
/* 原始SQL内容 */
第二步:EXPLAIN深度解析

| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | o | ALL | NULL | 1587923 | Using where; Using filesort |
| 1 | SIMPLE | u | eq_ref | PRIMARY | 1 | NULL |
| 1 | SIMPLE | p | eq_ref | PRIMARY | 1 | NULL |
问题暴露:
- 主表orders全表扫描(type=ALL)
- 出现致命filesort(Using filesort)
- 扫描行数高达158万+
第三步:索引手术刀
-- 复合索引(create_time+status覆盖查询条件)
ALTER TABLE orders ADD INDEX idx_crtime_status (create_time, status);
-- 包含排序字段的覆盖索引
ALTER TABLE orders ADD INDEX idx_amount_crtime (order_amount DESC, create_time);
(超级重要) 索引设计原则:
- 最左前缀原则:把等值查询字段放前面
- 覆盖索引:包含WHERE、ORDER BY、SELECT字段
- 避免过度索引:每个新增索引都会降低写性能
第四步:SQL语句重构
优化后SQL:
SELECT o.order_id, u.username, p.product_name
FROM orders o FORCE INDEX(idx_crtime_status)
STRAIGHT_JOIN users u ON o.user_id = u.user_id
STRAIGHT_JOIN products p ON o.product_id = p.product_id
WHERE o.create_time BETWEEN '2023-01-01' AND '2023-12-31'
AND o.status IN (1,3,5)
ORDER BY o.order_amount DESC
LIMIT 1000;
改动点解析:
FORCE INDEX强制使用新建索引STRAIGHT_JOIN控制连接顺序- 移除不必要的LEFT JOIN(业务确认后)
第五步:执行计划对比
优化后EXPLAIN:
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | o | range | idx_crtime_status | 89234 | Using index condition |
| 1 | SIMPLE | u | eq_ref | PRIMARY | 1 | NULL |
| 1 | SIMPLE | p | eq_ref | PRIMARY | 1 | NULL |
效果提升:
- 扫描行数从158万→8.9万
- 消除filesort
- 索引覆盖率从0→100%
第六步:参数调优(进阶技巧)
# my.cnf关键参数调整
innodb_buffer_pool_size = 16G
sort_buffer_size = 8M
read_rnd_buffer_size = 4M
(避坑指南) 不要盲目复制网上的配置模板!一定要根据实际内存大小调整。
第七步:终极武器——业务妥协
和产品经理Battle后的成果:
- 取消默认排序(改为按时间倒序)
- 分页查询限制最大页数
- 异步导出大数据量报表
性能对比报告
| 指标 | 优化前 | 优化后 | 提升倍数 |
|---|---|---|---|
| 执行时间 | 23.1s | 0.18s | 128x |
| 扫描行数 | 158w | 8.9w | 17x |
| CPU占用 | 98% | 15% | - |
| 锁等待时间 | 456ms | 0ms | - |
避坑锦囊(血泪经验)
- 永远不要相信ORM框架生成的SQL(重要的事情说三遍!)
- 分页查询一定要加
ORDER BY确定性排序 LIKE '%keyword%'是性能杀手,改用ES搜索- 定期使用
OPTIMIZE TABLE整理碎片(特别是频繁更新的表)
课后作业
试着用今天的方法分析你自己的慢SQL:
- 打开慢查询日志
- 用EXPLAIN查看执行计划
- 检查是否缺少合适索引
- 是否存在不必要的数据扫描
遇到卡点欢迎在评论区交流!下期预告:《MySQL索引设计的二十二条军规》

被折叠的 条评论
为什么被折叠?



