文章目录
真实踩坑:每秒处理3000单的系统突然瘫痪
上周三凌晨两点,我们电商平台的订单处理系统突然响应时间飙升到8秒!监控大屏直接飘红(血压也同步飙升),DBA老张抄起键盘就开始查慢日志,结果发现有个统计未发货订单的SQL,单次执行竟然要6.3秒!!!
一、慢查询终极定位术(附诊断流程图)
1. 开启慢查询日志的正确姿势(90%人都踩过的坑)
-- (超级重要)必须开启这三剑客
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 0.5; -- 建议0.3-1秒
SET GLOBAL log_queries_not_using_indexes = ON;
2. 用EXPLAIN看执行计划就像做CT扫描
看到这个执行计划了吗(手指屏幕)?type列显示ALL说明全表扫描,rows列显示扫了200万行,Extra里还有Using temporary和Using filesort这两个性能杀手!
二、索引优化的骚操作(教科书上不会写的)
1. 联合索引的排列组合玄学
错误示范:
ALTER TABLE orders ADD INDEX idx_status_time(status,create_time);
正确姿势:
ALTER TABLE orders ADD INDEX idx_time_status(create_time,status);
(惊不惊喜?把时间放前面能让范围查询更高效)
2. 隐式类型转换引发的血案
某次线上事故的元凶SQL:
SELECT * FROM users WHERE mobile = 13800138000; -- mobile字段是varchar类型!
优化方案:
SELECT * FROM users WHERE mobile = '13800138000'; -- 加上引号立省3秒
三、SQL语句重构的魔术手法
1. 用JOIN代替子查询的魔法
原语句(执行时间8.2秒):
SELECT * FROM products
WHERE category_id IN (
SELECT id FROM categories WHERE type = 'electronics'
);
优化后(0.3秒搞定):
SELECT p.* FROM products p
JOIN categories c ON p.category_id = c.id
WHERE c.type = 'electronics';
2. 分页查询的终极优化方案
传统写法(越往后越慢):
SELECT * FROM orders
ORDER BY id DESC
LIMIT 1000000, 20; -- 百万级偏移量要命
优化黑科技:
SELECT * FROM orders
WHERE id < 上次查询的最小ID
ORDER BY id DESC
LIMIT 20; -- 速度直接起飞
四、参数调优的魔鬼细节(调错一个参数毁所有)
1. 这三个参数必须调校:
- innodb_buffer_pool_size:建议设物理内存的70%
- thread_cache_size:根据Threads_created状态调整
- max_connections:别傻乎乎设10000,500-2000更稳妥
2. 临时表空间爆掉的紧急处理
某次大促的血泪教训:当看到created_tmp_disk_tables
暴增时,立即调整:
SET GLOBAL tmp_table_size = 256*1024*1024;
SET GLOBAL max_heap_table_size = 256*1024*1024;
五、实战复盘:从6.3秒到0.02秒的蜕变
原慢SQL:
SELECT COUNT(*) FROM orders
WHERE status = 1
AND create_time BETWEEN '2023-01-01' AND '2023-12-31'
AND user_id IN (SELECT id FROM users WHERE vip_level > 3);
分步优化过程:
- 发现status字段基数太低(只有5种状态),去掉该条件
- 把子查询改为JOIN操作
- 创建复合索引(create_time, user_id)
- 改用覆盖索引避免回表
最终优化版:
SELECT COUNT(o.id) FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.create_time BETWEEN '2023-01-01' AND '2023-12-31'
AND u.vip_level > 3;
六、DBA私藏工具箱大公开
- Percona Toolkit的杀手锏:
pt-query-digest slow.log > analysis.txt
- MySQL自带的性能分析神器:
SHOW PROFILE FOR QUERY 123;
- 实时监控利器:
SELECT * FROM sys.session WHERE time_ms > 1000;
结语:慢查询优化是门艺术
记得上个月优化过一个统计报表SQL,原本需要跑2小时,经过索引调整+业务逻辑优化+历史数据归档,现在只要3分钟!所以老铁们,遇到慢查询千万别慌,按照这个路线图一步步来:
- 精准定位(慢日志+EXPLAIN)
- 索引手术(别乱建索引!)
- SQL整形(重写比调参管用)
- 参数微调(小心驶得万年船)
- 架构升级(必要时上缓存、分库分表)
下次遇到数据库卡成PPT的时候,记得把这篇文章翻出来对照着操作,保准让DBA同事对你刮目相看!