需执行 SHOW GLOBAL VARIABLES LIKE 'slow_query_log' 确认全局启用状态,值为 ON 表示已开启,并通过 slow_query_log_file 查看日志路径;配置须写入 my.cnf 的 [mysqld] 段并重启生效。

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










