分析慢 SQL 的核心是定位性能瓶颈(如全表扫描、索引失效、锁等待等),并针对性优化。以下是一套标准化的分析流程,从日志获取到根因定位,再到优化验证:

一、第一步:获取慢 SQL(开启并查看慢查询日志)
首先确保慢查询日志已开启,才能捕获到慢 SQL。
-
检查 / 开启慢查询日志 登录 MySQL 执行命令,查看当前配置:
-- 查看是否开启(ON为开启,OFF为关闭) SHOW VARIABLES LIKE 'slow_query_log'; -- 查看慢查询阈值(单位:秒,默认10秒,可根据业务调整为1秒) SHOW VARIABLES LIKE 'long_query_time'; -- 临时开启(重启MySQL后失效,生产环境需在my.cnf中配置永久生效) SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1; -- 阈值设为1秒,捕获更精细的慢SQL
-
查看慢查询日志内容 先找到日志路径:
SHOW VARIABLES LIKE 'slow_query_log_file';
再通过服务器命令查看日志(如 Linux):
# 直接查看最新日志 cat /var/lib/mysql/xxx-slow.log # 或用MySQL自带工具mysqldumpslow分析(按执行次数排序,取前10条) mysqldumpslow -s c -t 10 /var/lib/mysql/xxx-slow.log
二、第二步:用EXPLAIN
分析 SQL 执行计划(核心步骤)
拿到慢 SQL 后,最关键的是通过EXPLAIN
查看 MySQL 的 "执行思路",定位瓶颈。
1. 基本用法
在慢 SQL 前加EXPLAIN
,例如:
EXPLAIN SELECT * FROM user WHERE age > 30 AND name LIKE '%张三%';
执行后会输出 12 列关键信息,重点关注以下 6 列:
列名 | 核心含义 | 异常信号(需优化) |
---|---|---|
id | SQL 执行顺序(数字越大越先执行,相同则按从上到下顺序) | 无异常,但需理解多表关联时的执行逻辑 |
select_type | 查询类型(如 SIMPLE = 简单查询、SUBQUERY = 子查询、JOIN = 关联查询) | 出现ALL (全表扫描)、filesort (文件排序)、using temporary (临时表) |
table | 当前行正在访问的表 | 无直接异常,但需结合其他列判断 |
type | 表的访问方式(性能从好到差:system > const > eq_ref > ref > range > index > ALL ) |
出现ALL (全表扫描,数据量大时必慢)、index (全索引扫描) |
key | 实际使用的索引(NULL 表示未使用索引) |
为NULL 且type 是ALL (未走索引) |
Extra | 额外执行信息(最能暴露问题的列) | 包含Using filesort (需优化排序)、Using temporary (需优化临时表)、Using where (过滤在内存完成,无大问题) |
2. 常见EXPLAIN
异常及原因
- 异常 1:type=ALL(全表扫描) 原因:未建索引、索引失效(如
LIKE '%xx'
、函数操作索引列、类型不匹配)。 - 异常 2:Extra=Using filesort原因:排序字段未走索引,MySQL 需在内存 / 磁盘中手动排序(数据量大时极慢)。
- 异常 3:Extra=Using temporary 原因:需创建临时表存储中间结果(如
GROUP BY
未走索引、多表关联排序未优化)。

三、第三步:补充分析工具(深入定位细节)
除了EXPLAIN
,还可结合以下工具获取更具体的性能数据:
-
EXPLAIN ANALYZE
(MySQL 8.0.18 + 支持) 比EXPLAIN
更精准,会实际执行 SQL 并返回真实的执行时间、行数等(注意:生产环境执行前需评估 SQL 是否会锁表或消耗资源):sql
EXPLAIN ANALYZE SELECT * FROM user WHERE age > 30;
-
查看 SQL 执行时间和锁等待 通过
SHOW PROFILE
查看 SQL 执行的每个阶段耗时(需先开启):sql
-- 开启 profiling SET profiling = ON; -- 执行慢SQL SELECT * FROM user WHERE age > 30; -- 查看最近一次SQL的执行详情 SHOW PROFILE FOR QUERY 1; -- 1是SQL的ID,可通过SHOW PROFILES查看
若耗时集中在
Sending data
(数据传输)或Waiting for table level lock
(表锁等待),需进一步优化数据量或锁策略。
四、第四步:常见慢 SQL 根因及优化方向
根据上述分析,定位根因后针对性优化:
常见根因 | 优化方案 |
---|---|
1. 未建索引 / 索引失效 | - 给过滤条件(WHERE )、排序(ORDER BY )、关联(JOIN ON )字段建索引- 避免索引失效:不用LIKE '%xx' (改用LIKE 'xx%' )、不函数操作索引列(如DATE(created_at) = '2024-01-01' 改为created_at BETWEEN '2024-01-01 00:00:00' AND '2024-01-01 23:59:59' ) |
2. 全表扫描(数据量大) | - 建合适索引- 分表分库(如按时间分表、按用户 ID 分库)- 避免SELECT * ,只查需要的字段(减少数据传输和内存消耗) |
3. 排序 / 分组未走索引 | - 给ORDER BY/GROUP BY 的字段建联合索引 (如WHERE age >30 ORDER BY create_time ,建索引(age, create_time) )- 减少排序数据量(先过滤再排序) |
4. 多表关联效率低 | - 确保关联字段(JOIN ON )有索引- 小表驱动大表(如SELECT * FROM 小表 JOIN 大表 ON ... )- 避免LEFT JOIN 时右边表的过滤条件写在WHERE 中(会导致LEFT JOIN 变INNER JOIN ) |
5. 事务 / 锁等待 | - 缩短事务时长(避免在事务中执行非数据库操作,如 RPC 调用)- 用行锁(InnoDB )替代表锁,避免长事务占用锁资源 |
五、第五步:优化后验证
优化后需重新执行EXPLAIN
和慢 SQL,确认:
type
从ALL
提升到ref
/range
等更优级别;key
列显示使用了目标索引;Extra
中无Using filesort
/Using temporary
;- 实际执行时间显著缩短(可通过
EXPLAIN ANALYZE
或业务监控确认)。
总结
分析慢 SQL 的核心流程:获取慢日志 → 用 EXPLAIN 看执行计划 → 定位根因(无索引 / 全表扫描 / 排序异常等) → 针对性优化 → 验证效果 。其中,EXPLAIN
是最关键的工具,需重点掌握其输出列的含义和异常信号。
