分析慢 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是最关键的工具,需重点掌握其输出列的含义和异常信号。
