mysql中的慢查询日志分析与优化方法

来源:这里教程网 时间:2026-02-28 20:46:28 作者:

如何确认慢查询日志是否已启用并定位日志路径

MySQL 默认不开启慢查询日志,必须手动配置生效。直接查

slow_query_log
变量只能反映当前会话状态,真正要看全局是否启用,得执行:
SHOW GLOBAL VARIABLES LIKE 'slow_query_log';
如果值为
OFF
,说明没开;同时检查
slow_query_log_file
的值,它指向实际日志文件路径(如
/var/lib/mysql/slow.log
),但该路径可能因 MySQL 启动用户权限不足而写入失败——常见现象是日志文件存在但大小始终为 0。

关键配置项需写在

my.cnf
[mysqld]
段落中,并重启服务才生效:
slow_query_log = ON<br>slow_query_log_file = /var/log/mysql/mysql-slow.log<br>long_query_time = 1.0<br>log_queries_not_using_indexes = OFF
long_query_time
单位是秒,且从 MySQL 5.7 起支持毫秒级(如
0.1
),但注意:该阈值对微秒级时间不敏感,实际记录以整数秒四舍五入判断;
log_queries_not_using_indexes
开启后会导致大量简单 SELECT 被记录,干扰分析,建议初期关闭。

用 mysqldumpslow 快速提取高频慢查询模式

mysqldumpslow
是 MySQL 自带的解析工具,比直接
grep
awk
更可靠,因为它能自动归一化 SQL(把
WHERE id = 123
WHERE id = 456
视为同一类)。常用组合:

mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log
:按出现次数(
c
)排序,取前 10 条
mysqldumpslow -s t -g "SELECT.*FROM orders" /var/log/mysql/mysql-slow.log
:筛选含
SELECT ... FROM orders
的语句,并按总耗时(
t
)排序

注意:

mysqldumpslow
不解析带引号的字符串参数,若 SQL 中有类似
WHERE name = '张三'
,会被统一为
WHERE name = '?' 
,所以归类准确;但如果语句里混用反引号、大小写混乱或空格不一致,仍可能被当作不同模式——建议先用
mysqlbinlog
或第三方工具(如
pt-query-digest
)做二次校验。

EXPLAIN 输出中哪些字段真正影响性能判断

对慢查询语句执行

EXPLAIN
后,重点盯住这四个字段:

type
:值为
ALL
表示全表扫描,必须优化;
range
ref
属于可接受范围;
const
最理想(主键/唯一索引等值匹配)
key
:显示实际使用的索引名;若为
NULL
,说明没走索引,哪怕
possible_keys
有值
rows
:MySQL 预估扫描行数;若远大于结果集行数(可用
SELECT COUNT(*)
对比),说明索引选择性差或统计信息过期,需运行
ANALYZE TABLE
Extra
:出现
Using filesort
Using temporary
是典型瓶颈信号,通常意味着缺失覆盖索引或
ORDER BY
/
GROUP BY
字段未被索引包含

特别注意:MySQL 8.0+ 的

EXPLAIN FORMAT=JSON
会暴露更细粒度信息,比如
used_columns
index_condition
,能帮你确认是否发生了索引下推(ICP)——这对复合索引设计很关键。

为什么加了索引查询还是慢?几个隐蔽原因

常见误区是“建了索引就万事大吉”,但以下情况会让索引失效或低效:

对索引字段使用函数或表达式:
WHERE YEAR(create_time) = 2023
→ 改成
WHERE create_time >= '2023-01-01' AND create_time 
隐式类型转换:
user_id
VARCHAR
,但查询写成
WHERE user_id = 123
→ MySQL 会放弃索引转为全表扫描
最左前缀未满足:
INDEX(a, b, c)
,查询只用
WHERE b = ? AND c = ?
,无法命中
统计信息陈旧:
INFORMATION_SCHEMA.STATISTICS
中的
CARDINALITY
值不准,导致优化器选错执行计划;定期执行
ANALYZE TABLE table_name
可缓解

还有一个容易被忽略的点:InnoDB 的聚簇索引特性决定了,如果

SELECT *
查询的表没有合适覆盖索引,即使
WHERE
条件走了索引,仍需回表读取完整行数据——此时
rows
小但响应慢,应考虑添加覆盖索引或减少返回字段。

相关推荐