仅靠慢查询日志无法区分索引不合理与sql写法问题,需结合log_queries_not_using_indexes、min_examined_row_limit及explain分析;因日志仅记录耗时和sql文本,不包含执行计划,无法判断是否走索引或为何失效。

直接结论:仅靠慢查询日志本身无法区分“索引不合理”和“SQL写法问题”,必须配合 log_queries_not_using_indexes + min_examined_row_limit 组合使用,并辅以 EXPLAIN 验证。
为什么慢查询日志默认不暴露索引问题?
慢查询日志只记录「执行时间超过 long_query_time」的 SQL,而一条 SQL 慢,可能是因全表扫描(没走索引),也可能是走了索引但回表太多、索引选择性差、或 WHERE 条件写法导致索引失效。日志里只存原始 SQL 和耗时,不带执行计划,所以你看到 SELECT * FROM orders WHERE status = 'pending' 耗时 8 秒,根本不知道它到底有没有用索引。
如何让慢日志主动标记“疑似索引问题”的 SQL?
启用两个关键开关,让 MySQL 主动帮你筛选出更可疑的候选:
-
SET GLOBAL log_queries_not_using_indexes = ON:强制记录所有未走索引的查询(哪怕只查 1 行、耗时 1ms) -
SET GLOBAL min_examined_row_limit = 1000:只记录扫描行数 ≥ 1000 的语句,过滤掉小表误伤
这两个参数组合后,日志里出现的条目,基本就是「本该走索引却没走」+「数据量不小」的双重嫌疑对象。注意:log_queries_not_using_indexes 生产环境绝不能长期开着,否则日志爆炸;只在排查期临时开 10–30 分钟即可。
从日志里抓到可疑 SQL 后,下一步必须做 EXPLAIN
拿到日志里的 SQL,别急着加索引。先在测试库或从库上跑 EXPLAIN,重点看三列:
-
type:如果是ALL或index,基本确认全表/全索引扫描 -
key:为NULL表示完全没走索引;有值但rows很大(比如 > 表总行数 20%),说明索引效率低 -
Extra:出现Using filesort或Using temporary时,即使走了索引,也可能因排序/分组字段没覆盖而退化
例如:EXPLAIN SELECT * FROM user WHERE name LIKE '%john%' 显示 type=ALL 且 key=NULL,说明 name 上的索引完全失效——这不是索引没建,而是 LIKE 左模糊导致无法使用 B+Tree 索引。
容易忽略的陷阱:索引存在 ≠ 索引被用
很多开发者看到「这个字段建了索引」就以为万事大吉,但实际中常见干扰项包括:
- 隐式类型转换:
WHERE user_id = '123'(user_id是INT)会强制全表扫描 - 函数操作:
WHERE DATE(create_time) = '2026-06-13'使索引失效 - 联合索引顺序错:
INDEX(a,b,c),但查询只用WHERE c = 1,无法命中 - 统计信息过期:
ANALYZE TABLE没跑过,优化器误判索引成本过高而放弃
这些情况都会让慢日志里出现“已建索引却仍慢”的假象,真正原因藏在执行计划里,不在日志本身。











