在业务系统运行过程中,数据库响应变慢往往源于少数执行效率低的SQL语句。要彻底解决这类问题,不能靠猜,而要建立从日志到执行计划的完整排查路径,逐步定位根源并验证优化效果。

一、开启并获取慢查询日志
慢查询日志是定位慢SQL最直接的数据来源。在MySQL中,可以通过参数控制是否记录执行时间超过阈值的语句。
-- 查看慢查询相关配置 SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time'; -- 临时开启慢查询日志,阈值设为1秒 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 查看日志文件位置 SHOW VARIABLES LIKE 'slow_query_log_file';
日志中会记录每条慢SQL的执行时间、锁等待时间、扫描行数等信息。人工翻阅日志效率较低,可借助mysqldumpslow工具做汇总:
# 按平均耗时排序取前10条 mysqldumpslow -s at -t 10 /var/lib/mysql/slow.log
二、通过实时会话发现阻塞
有时慢SQL正在执行,还未写入日志。此时可用SHOW PROCESSLIST查看当前连接状态:
-- 查看运行中的线程,重点看Time和State列 SHOW PROCESSLIST; -- 只筛出执行超过30秒的会话 SELECT * FROM information_schema.PROCESSLIST WHERE TIME > 30 AND COMMAND <> 'Sleep';
若发现某语句长时间处于Sending data或Locked状态,往往就是需要优先处理的对象。
三、用执行计划分析语句
拿到可疑SQL后,在前面加EXPLAIN即可查看优化器选定的执行路径。
EXPLAIN SELECT u.name, o.amount FROM user u JOIN orders o ON u.id = o.user_id WHERE u.city = 'Beijing' AND o.create_time > '2023-01-01';
关键字段含义如下:
| 字段 | 说明 |
|---|---|
| type | 访问类型,ALL表示全表扫描,index或range较优 |
| key | 实际使用的索引,NULL代表未走索引 |
| rows | 预估扫描行数,越大越慢 |
| Extra | 如出现Using filesort、Using temporary需警惕 |
常见索引失效写法
- 对索引列使用函数,如
WHERE YEAR(create_time)=2023 - 隐式类型转换,如字符串字段用数字比较
- 前导模糊查询,如
LIKE '%abc'
四、优化并验证
确认问题后,可建立联合索引或改写SQL。以之前的查询为例,建立覆盖索引:
-- 为常用过滤与关联字段建索引 CREATE INDEX idx_user_city ON user(city); CREATE INDEX idx_orders_user_time ON orders(user_id, create_time);
再次执行EXPLAIN,若type变为ref或range,rows明显下降,说明优化生效。最后回到慢日志观察同类语句是否还出现。
定位慢SQL的核心习惯是:先有数据(日志、会话),再谈猜测;用执行计划代替肉眼看语句,用前后对比确认改动价值。
五、小结
从慢查询日志采集,到实时会话补充,再到执行计划解读与索引调整,是一条可复用的排查链路。掌握这套流程,大部分SQL性能问题都能在可控时间内收敛。