log_queries_not_using_indexes设了没日志,是因为它必须依赖slow_query_log=on才生效;若后者为off,则该参数无效,且受min_examined_row_limit、优化器实际判定、权限等多重限制。

log_queries_not_using_indexes 为什么设了没日志?
因为 log_queries_not_using_indexes 不是独立开关,它必须依赖 slow_query_log = ON 才会生效。如果 slow_query_log 是 OFF,哪怕你执行了 SET GLOBAL log_queries_not_using_indexes = ON,也不会写入任何日志。
验证方法很简单:
- 先查
SHOW VARIABLES LIKE 'slow_query_log';—— 必须返回ON - 再查
SHOW VARIABLES LIKE 'log_queries_not_using_indexes';—— 确认是ON - 最后执行一条明确不走索引的语句(比如对无索引字段
SELECT * FROM t WHERE name = 'x'),检查slow_query_log_file是否有新增条目
配置项之间有哪些关键依赖和陷阱?
log_queries_not_using_indexes 的触发不是“有没有建索引”,而是优化器实际执行时判定“本次查询放弃使用索引”。常见但容易误判的场景包括:
- 字段有索引,但
WHERE中用了函数(如WHERE DATE(create_time) = '2026-05-01')或隐式类型转换 - 索引列参与运算(如
WHERE id + 1 = 100) - 表数据极少(
rows 时默认不记录;MySQL 认为全表扫描比走索引更快) - 复合索引未满足最左前缀(如索引是
(a,b,c),却只查WHERE b = 1) -
OR条件中部分分支无法用索引,导致整个条件退化
注意:EXPLAIN 输出中 key 为 NULL、type 为 ALL 或 index,基本就对应会被该日志捕获。
动态设置 vs 配置文件,哪个更稳妥?
生产环境推荐优先改配置文件(如 /etc/mysql/mysql.conf.d/mysqld.cnf),因为重启后不会丢失。动态 SET GLOBAL 设置在服务重启后会失效,且部分变量(如 slow_query_log_file)修改后需手动 FLUSH LOGS 才能切换到新文件。
配置文件中至少要加这四行:
slow_query_log = ON slow_query_log_file = /var/log/mysql/slow.log long_query_time = 0.1 log_queries_not_using_indexes = ON
补充说明:
-
long_query_time设为0.1(100ms)才能捕获更多潜在低效查询,设为0会记录所有查询,日志爆炸风险极高 - 确保 MySQL 进程对
slow_query_log_file路径有写权限,否则日志静默失败 - 若用
log_output = TABLE,需确认mysql.slow_log表存在且可写,但生产环境仍建议用FILE配合pt-query-digest分析
为什么有些明显没走索引的 SQL 还是没进日志?
除了前面说的 slow_query_log 关闭问题,还有几个硬性限制:
-
min_examined_row_limit默认为 0,但如果被调大(比如设成 1000),那么扫描行数不足的查询即使没走索引也不会记录 -
log_throttle_queries_not_using_indexes可限制单位时间内的记录条数,默认为 0(不限制),但设为非零值后可能漏记高频小查询 - 管理语句(如
ANALYZE TABLE、ALTER TABLE)默认不记,需额外开启log_slow_admin_statements - MySQL 8.0+ 对“未用索引”的判定更严格,某些旧版本会记的 case,8.0 可能因统计信息更新或优化器改进而跳过
最容易被忽略的是:日志写入发生在查询执行完成且锁全部释放之后,所以高并发下日志顺序 ≠ 执行顺序,排查时别只盯时间戳。











