MySQL 慢查询怎么排查?
MySQL 慢查询排查遵循 "发现 → 定位 → 分析 → 优化 → 验证" 五步法:
- 步骤①:开启慢查询日志,捕获慢 SQL。
- 步骤②:查看慢查询日志,定位问题 SQL。
- 步骤③:使用
EXPLAIN分析执行计划。 - 步骤④:根据分析结果优化(索引/SQL 改写)。
- 步骤⑤:验证优化效果,对比执行时间。
一句话总结:开启慢查询日志定位问题 SQL,用 EXPLAIN 分析执行计划,针对性优化索引或改写 SQL,最后验证效果。
深度解析
一、开启慢查询日志
-- 1. 查看慢查询日志配置
SHOW VARIABLES LIKE '%slow_query%';
-- slow_query_log: OFF/ON(是否开启)
-- slow_query_log_file: 慢查询日志文件路径
-- 2. 查看慢查询阈值(默认 10 秒)
SHOW VARIABLES LIKE 'long_query_time';
-- 3. 动态开启慢查询日志(重启失效)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 设置为 1 秒
-- 4. 是否记录没走索引的 SQL
SHOW VARIABLES LIKE 'log_queries_not_using_indexes';
SET GLOBAL log_queries_not_using_indexes = ON;
配置文件方式(永久生效):
# my.cnf
[mysqld]
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = ON
关键参数说明:
slow_query_log:是否开启慢查询日志long_query_time:慢查询阈值,超过该时间的 SQL 会被记录(单位:秒,可精确到微秒)log_queries_not_using_indexes:是否记录没走索引的 SQL(即使很快)min_examined_row_limit:扫描行数少于此值不记录(避免记录简单查询)
二、定位慢查询 SQL
常用命令:
# 使用 mysqldumpslow 分析慢查询日志
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# 输出示例
Count: 5 Time=10.23s Lock=0.00s Rows=1000.0
SELECT * FROM orders WHERE create_time > '2024-01-01'
-- MySQL 5.7+ 使用 sys 库查询慢 SQL
SELECT
query_id,
LEFT(query, 100) AS query_preview,
exec_count,
avg_latency / 1000000 AS avg_ms,
rows_examined,
rows_sent
FROM sys.statements_with_runtimes_in_95th_percentile
ORDER BY avg_latency DESC
LIMIT 10;
三、使用 EXPLAIN 分析执行计划
-- 基本用法
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
-- MySQL 8.0+ 推荐使用 EXPLAIN ANALYZE(显示实际执行时间)
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 100;
EXPLAIN 输出字段详解:
type 访问类型性能排序:
实战案例分析:
-- 案例 1:全表扫描(需要优化)
EXPLAIN SELECT * FROM orders WHERE amount > 100;
-- type: ALL, key: NULL, rows: 1000000
-- 优化:给 amount 加索引
-- 案例 2:索引范围扫描(较好)
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
-- type: ref, key: idx_user_id, rows: 50
-- 已经走了索引
-- 案例 3:覆盖索引(最优)
EXPLAIN SELECT user_id, status FROM orders WHERE user_id = 100;
-- type: ref, key: idx_user_id, Extra: Using index
-- 不需要回表,性能最佳
四、常见慢查询场景与优化
优化实战示例:
-- 优化前:全表扫描 + 文件排序
EXPLAIN SELECT * FROM orders
WHERE status = 1
ORDER BY create_time DESC
LIMIT 100;
-- type: ALL, Extra: Using where; Using filesort
-- 优化:添加联合索引
CREATE INDEX idx_status_create_time ON orders(status, create_time);
-- 优化后:索引范围扫描 + 索引排序
-- type: ref, Extra: Using index condition
-- 优化前:索引失效(函数操作)
EXPLAIN SELECT * FROM orders
WHERE YEAR(create_time) = 2024;
-- type: ALL(索引失效!)
-- 优化后:改写为范围查询
EXPLAIN SELECT * FROM orders
WHERE create_time >= '2024-01-01'
AND create_time < '2025-01-01';
-- type: range, key: idx_create_time
浙公网安备 33010602011771号