慢查询日志不记录锁等待时间,仅统计语句总执行耗时;需通过performance_schema的events_statements_history_long表(LOCK_TIME字段)或events_waits_history_long等定位锁等待。

慢查询日志默认不记录锁等待时间
MySQL 的 slow_query_log 只统计语句从开始执行到**返回结果**的总耗时(即 query_time),而锁等待(如等 innodb_row_lock_waits)发生在执行阶段内部,不会被直接计入 query_time——除非锁等待本身拖长了整体执行时间。换句话说:单纯开启慢查询日志,抓不到“在锁上卡了 3 秒但执行逻辑很快”的情况。
常见错误现象:
- 设置 long_query_time = 1,但某条 UPDATE 明明卡住 5 秒才返回,日志里却没出现;
- 实际是事务 A 持有行锁,事务 B 在 SELECT ... FOR UPDATE 时阻塞 4.8 秒后执行 0.2 秒完成,总耗时 5.0 秒 → 这条会记入慢日志;
- 但如果事务 B 等锁 0.9 秒、执行 0.1 秒,总耗时 1.0 秒(未超阈值),就不会记录 —— 你完全看不到它曾严重受锁影响。
- 必须开启
log_slow_admin_statements = ON(部分管理语句也需捕获) -
log_queries_not_using_indexes = OFF建议关闭,避免干扰主目标 - 关键:配合
innodb_print_all_deadlocks = ON查死锁,但死锁 ≠ 锁等待
真正能暴露锁等待的替代方案:performance_schema
要定位“执行中卡在锁上”,performance_schema 是更直接的路径,尤其依赖以下三张表:
-
events_statements_history_long:含每条语句的TIMER_WAIT(纳秒级总耗时)和LOCK_TIME(明确分离出锁等待耗时) -
events_waits_history_long:可查到具体等待事件,如wait/synch/mutex/innodb/lock_mutex或wait/io/table/sql/handler -
data_locks+data_lock_waits(MySQL 8.0.1+):实时看到谁在等谁的哪一行/页锁
示例:查最近锁等待超 100ms 的语句
SELECT esh.THREAD_ID, esh.SQL_TEXT, esh.LOCK_TIME/1000000000 AS lock_sec FROM performance_schema.events_statements_history_long esh WHERE esh.LOCK_TIME > 100000000;
注意:LOCK_TIME 是语句生命周期内所有锁等待的累计值,不是单次最长等待;且仅当 performance_schema 中对应 instrument(如 statement/sql/update)已启用才有效。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
配合 general_log 和 processlist 做交叉验证
当怀疑某类操作频繁锁等待,但 slow_query_log 和 performance_schema 都没抓到明显线索时,可临时启用 general_log 并过滤状态变化:
- 开
general_log = ON,日志输出到表(log_output = 'TABLE')便于 SQL 查询 - 查
mysql.general_log中连续出现的Query+Quit之间间隔异常长的记录(说明连接卡住) - 同时查
SHOW PROCESSLIST中状态为Waiting for table metadata lock或Updating且Time值持续增长的线程
特别注意:Waiting for table metadata lock 往往是 DDL(如 ALTER TABLE)阻塞了 DML,这类锁不走 InnoDB 行锁机制,data_locks 表里查不到,但 processlist 能第一时间暴露。
线上环境慎用的高开销组合
想靠日志“全自动”捕获所有锁等待,容易踩两个坑:
-
performance_schema开全量 instruments(尤其是wait/类)会使 QPS 下降 10%~30%,MySQL 5.7 尤其敏感 -
general_log写磁盘极易打满 IO,写表模式也会显著拖慢INSERT性能 -
slow_query_log自身虽低开销,但若设long_query_time = 0,会把所有语句都写入,日志体积爆炸且掩盖真实慢点
实际调试建议:先用 SHOW ENGINE INNODB STATUS\G 抓当前锁信息快照,再针对性打开 performance_schema 中少数关键 instrument(如 statement/sql/update, wait/lock/innoDB/row_lock),持续 5–10 分钟后关掉 —— 不要长期开着等“意外发生”。

















