文章目录
前言:那个让我加班的深夜
上周三凌晨1点,我盯着屏幕上跑得像蜗牛一样的统计报表查询(足足跑了37秒!!!),咖啡杯已经见底。DBA发来的监控截图里,这个SQL在慢查询榜上稳居Top 3(红色警告特别刺眼)。从那天起,我踏上了慢SQL优化的不归路…
一、慢SQL的三大杀手锏(血泪教训)
-
索引缺失综合症
就像图书馆没有目录卡(你见过有人翻遍所有书架找书吗?),最常见的慢查询病因。上周那个37秒的查询,WHERE条件里有created_at和user_type字段——但这两个字段竟然没有联合索引! -
JOIN地狱连环套
五表联查不是问题,但当每个JOIN条件都没索引时(特别是百万级数据表),查询计划器会直接摆烂。我见过最夸张的案例:一个包含3个LEFT JOIN的查询,执行时间从8秒优化到0.2秒,就靠调整JOIN顺序+索引! -
分页黑洞
LIMIT 100000, 20这种写法简直就是性能杀手(MySQL真的会把前100000行都读一遍)。后来我们用WHERE id > 上次最大ID改写,性能直接提升20倍!
二、必备武器库(工具篇)
1. EXPLAIN全家桶
EXPLAIN FORMAT=JSON
SELECT * FROM orders
WHERE user_id = 123
AND status = 'completed';
重点关注:
- type列:出现
ALL(全表扫描)请立即拉响警报!!! - rows列:估算扫描行数 vs 实际返回行数(差值越大问题越大)
- Extra列:看到
Using filesort或Using temporary就要警惕
2. 慢查询日志分析(配置秘籍)
# my.cnf配置
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 # 超过1秒的查询全记录
log_queries_not_using_indexes = 1 # 捕获无索引查询(超级重要)
用mysqldumpslow工具分析:
mysqldumpslow -s t /var/log/mysql/slow.log | head -10
三、实战优化案例(手把手教学)
案例1:电商订单查询优化
原始SQL(执行时间8.4秒):
SELECT * FROM orders
WHERE user_id = 12345
AND create_time BETWEEN '2023-01-01' AND '2023-06-30'
ORDER BY total_price DESC
LIMIT 1000,20;
优化三部曲:
-
加联合索引(注意顺序!)
ALTER TABLE orders ADD INDEX idx_user_time (user_id, create_time); -
改写分页逻辑
SELECT * FROM orders WHERE user_id = 12345 AND create_time BETWEEN '2023-01-01' AND '2023-06-30' AND id > 1000 -- 记住上次最大ID ORDER BY total_price DESC LIMIT 20; -
覆盖索引优化
SELECT id, total_price /* 只查需要的字段 */ FROM orders WHERE user_id = 12345 AND create_time BETWEEN '2023-01-01' AND '2023-06-30' ORDER BY total_price DESC LIMIT 1000,20;
最终效果:8.4秒 → 0.18秒!
案例2:报表统计SQL重生记
问题SQL:
SELECT COUNT(*) AS total, department
FROM employees
WHERE salary > 10000
AND join_date > '2020-01-01'
GROUP BY department;
优化亮点:
- 把
COUNT(*)改成COUNT(1)(虽然新版MySQL差别不大,但老版本有效) - 创建
(join_date, salary, department)的联合索引 - 对于超大数据量,改用
物化视图预计算
四、防患未然的七个习惯
-
新建表必做三件事
- 主键设置(别用UUID!)
- 创建时间/更新时间字段
- 常用查询字段的联合索引
-
SQL审核流程(救了我团队无数次)
上线前必须检查:- WHERE条件字段是否有索引
- 是否有
SELECT * - 分页是否超过1000页
- 事务是否过大
-
定期健康检查
我的巡检清单:-- 索引使用统计 SELECT index_name, rows_used FROM sys.schema_index_statistics WHERE table_schema = 'your_db'; -- 冗余索引检测 SELECT * FROM sys.schema_redundant_indexes;
五、高级优化技巧(进阶级)
-
冷热数据分离
把半年前的订单归档到历史表,查询速度直接翻倍 -
列式存储引擎
对于分析型查询,试试TokuDB引擎(比InnoDB快10倍不是梦) -
巧用虚拟列
比如把JSON字段里的常用值提取成虚拟列+索引:ALTER TABLE products ADD COLUMN price DECIMAL(10,2) GENERATED ALWAYS AS (JSON_EXTRACT(spec, '$.price')) STORED, ADD INDEX idx_price (price);
六、避坑指南(血泪总结)
- 不要过度索引:每个索引都会降低写性能(我见过索引占数据量200%的表!)
- 隐式转换陷阱:
WHERE varchar_col = 123会导致全表扫描 - JOIN字段类型必须一致:
INT vs VARCHAR的类型不匹配是性能杀手 - 慎用OR条件:
WHERE a=1 OR b=2可能会破坏索引使用
结语:优化永无止境
经过两周的优化攻坚,那个37秒的查询现在只需要0.8秒。但优化的魅力就在于——永远有更好的方案等待发现。下次当你看到慢查询日志时,记住:这不是bug,这是提升技能的机会!(当然,最好别在凌晨1点遇到…)

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



