如何确认慢查询日志是否已启用并定位日志路径
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小但响应慢,应考虑添加覆盖索引或减少返回字段。
