文章目录
一、血泪开篇:那个差点让我加班的夜晚🌃
“啪!” 凌晨两点,值班手机突然响起警报——核心业务接口响应时间飙到20秒!(救命啊😱)打开监控一看,一条简单的订单查询SQL竟然成了性能黑洞。作为过来人,今天必须把压箱底的慢SQL优化套路全抖出来!
二、实用到爆的排查四板斧(建议收藏⭐)
1. 先找元凶:慢查询日志抓现行
-- 开启慢查询记录(线上慎用!)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 超过1秒的都记下来
2. EXPLAIN执行计划破案现场
看到Using filesort和Using temporary这两个红色警报(危险警告⚠️),说明你的SQL正在:
- 全表扫描(type=ALL)
- 创建临时表处理排序
- 文件排序而不是索引排序
3. 索引失效的六大骚操作(必看!!)
- 在where条件里搞计算:
WHERE YEAR(create_time)=2023
❌ - 隐式类型转换:
WHERE order_no=10086
(order_no是varchar)❌ - 最左匹配原则搞事情:建了(a,b,c)索引却只用b和c ❌
- 滥用
SELECT *
(特别是text/blob字段)❌ - 在索引列上用
NOT IN
或<>
❌ - 索引字段使用函数:
WHERE LEFT(name,3)='张'
❌
4. 参数调优的隐藏彩蛋
修改这两个参数立竿见影(适合紧急救援):
innodb_buffer_pool_size = 物理内存的70%
tmp_table_size = 64M # 防止临时表爆炸
三、实战案例:20秒→0.02秒的魔幻之旅
原罪SQL(危险示范):
SELECT * FROM orders
WHERE user_id=123
AND status IN(1,2,5)
ORDER BY create_time DESC
LIMIT 1000,20;
问题诊断:
- 全表扫描(没命中user_id索引)
- 文件排序(filesort)
- 深分页(limit 1000,20)
改造后的王者SQL:
ALTER TABLE orders ADD INDEX idx_uid_status_ctime(user_id,status,create_time);
SELECT id,order_no,amount
FROM orders FORCE INDEX(idx_uid_status_ctime)
WHERE user_id=123
AND status IN(1,2,5)
ORDER BY create_time DESC
LIMIT 20 OFFSET 1000;
优化效果:
- 执行时间:20s → 0.02s
- 扫描行数:10w+ → 1020行
四、高阶玩家必备技巧(老司机发车🚗)
1. 分页优化的骚操作
用游标分页代替传统分页:
SELECT * FROM orders
WHERE id > 上次最后一条ID
ORDER BY id
LIMIT 20;
2. 联合索引的排列组合玄学
记住这个口诀:等值查询放左边,范围查询放右边。比如:
- 好索引:
(shop_id, status, create_time)
- 烂索引:
(create_time, status, shop_id)
3. 冷热数据分离大法
把历史订单归档到历史表,核心表只保留半年数据。查询速度直接起飞🛫
五、防坑指南(都是血泪教训😭)
- 别迷信
FORCE INDEX
!可能今天有用,明天数据分布变了就爆炸💥 COUNT(*)
优化要慎重,上亿数据考虑用汇总表- 定期用
ANALYZE TABLE
更新统计信息(重要!) - 千万级数据联表查询,先把小表放前面
六、终极武器:优化思路脑图(右键保存!)
慢SQL优化流程:
1. 抓取慢查询 → 2. EXPLAIN分析 → 3. 检查索引
↳ 有索引但没用 → 检查索引失效情况
↳ 没合适索引 → 新建复合索引
4. 改写SQL逻辑 → 5. 业务层优化 → 6. 架构升级
七、结语:优化是门艺术🎨
记住这个真理:没有最好的优化方案,只有最适合当前业务场景的方案!(敲黑板)下次遇到慢SQL别慌,按这个流程走一遍,你也能成为同事眼中的"优化大神"!