log_queries_not_using_indexes与锁竞争无关,因其仅判断SQL是否命中索引,不记录锁等待状态;即使语句因行锁阻塞数秒,只要走索引就不会被记录,而未走索引的快速查询却会被误记。

不要开启 log_queries_not_using_indexes 来查锁竞争——它根本不会记录锁等待,只会把没走索引的 SQL 全塞进日志,且不管执行多快。
为什么 log_queries_not_using_indexes 和锁竞争无关
这个配置项只判断 SQL 是否命中索引,不关心是否被阻塞。哪怕一条 SELECT * FROM user WHERE id = 1 因为前序事务锁住了这行而等了 5 秒,只要它最终走了主键索引,就不会被记录;反过来,SELECT * FROM log WHERE created_at > '2026-01-01' 没建索引、执行仅 2ms,也会被强制记入慢日志。
锁等待时间是包含在 long_query_time 统计里的(MySQL 5.7+ 默认计入),但 log_queries_not_using_indexes 完全不参与这个逻辑。
- 它只做“索引覆盖检查”,不是“锁状态检查”
- 开启后,小表全扫、临时表 JOIN、函数索引失效等场景都会爆炸式写日志
- 日志里看不到
Locked by、Waiting for这类锁上下文信息
真正能暴露锁竞争的慢日志配置组合
要让慢日志帮你揪出锁问题,关键不是开错开关,而是让日志带出足够上下文:
- 必须设
long_query_time = 1(或更低),确保锁等待超时的语句能被捕获 - 开启
log_output = FILE(默认),保证日志格式完整(含时间戳、线程ID、锁等待时长) - 配合
min_examined_row_limit = 100过滤掉无意义的小结果集扫描 -
禁用
log_queries_not_using_indexes,避免噪音淹没真实锁阻塞案例
典型慢日志片段中,你会看到类似:
# Time: 2026-05-11T02:15:22.345678Z # User@Host: app[app] @ [10.0.1.23] Id: 12345 # Query_time: 4.231245 Lock_time: 4.229102 Rows_sent: 1 Rows_examined: 1 SET timestamp=1747016122; SELECT * FROM order WHERE order_no = 'ORD-20260511-XXXX';
注意 Lock_time: 4.229102 —— 这个值接近总耗时,就是强锁竞争信号。
比慢日志更直接的锁排查手段
依赖慢日志发现锁问题属于“事后回溯”,效率低且容易漏。线上应优先用实时手段:
- 执行
SHOW ENGINE INNODB STATUS\G,看LATEST DETECTED DEADLOCK和TRANSACTIONS部分 - 查询
performance_schema.data_lock_waits(MySQL 8.0+),直接看到谁在等谁的锁 - 用
SELECT * FROM information_schema.INNODB_TRX查当前长事务,结合INNODB_LOCKS和INNODB_LOCK_WAITS(5.7)定位链路 - 观察
innodb_row_lock_waits状态变量突增,说明锁争抢已成常态
这些方法不依赖日志开关,响应快,且能明确指出持有锁的 SQL 和等待方的会话 ID。
什么时候才该临时打开 log_queries_not_using_indexes
仅限两种场景,且必须搭配严格限制:
- 做全量索引健康检查:上线前确认所有高频查询都已覆盖索引,此时配合
min_examined_row_limit = 10000和long_query_time = 0.1,开 10 分钟即关 - 排查某张表突然 CPU 飙高:怀疑有隐式全表扫,临时开启 +
log_throttle_queries_not_using_indexes = 5防日志刷爆
任何情况下,都不该把它和锁分析混为一谈。锁问题藏在 Lock_time 字段、事务状态和等待图里,不在“有没有走索引”这个二值判断中。


















