mysql 8.0无“锁图谱”视图,需手动关联data_locks、data_lock_waits和metadata_locks三表拼出锁关系链;空结果多因锁采集器未启用,而非无锁争用。

查不到锁图谱,因为 MySQL 8.0 的 performance_schema 没有“锁图谱”这个概念或视图——它只有离散的锁状态快照表,比如 data_locks、data_lock_waits、metadata_locks,你需要自己拼出锁关系链。
为什么不能直接查“锁图谱”
MySQL 不提供可视化锁依赖图或自动拓扑分析功能。所谓“图谱”是运维人员对锁持有者、等待者、阻塞路径的逻辑还原结果,不是内置视图。很多用户执行 SELECT * FROM performance_schema.data_locks 后以为“看到锁了”,但没意识到:单张表只告诉你“谁锁了什么”,不告诉你“谁在等谁”或“为什么卡住”。
-
data_locks只存 GRANTED 状态的锁记录,WAITING 类型的锁不在其中(它属于请求未满足,尚未落地为锁实例) -
data_lock_waits只存实时等待对,一旦锁释放或等待超时,记录立即消失 - 没有
lock_graph、lock_dependency或类似命名的系统表
如何用 data_locks + data_lock_waits 拼出锁关系
这是最接近“图谱”的实操路径:先找等待,再反查持锁者,最后补上下文。必须三步连查,漏一环就断链。
- 第一步:确认存在等待关系
SELECT BLOCKING_ENGINE_TRANSACTION_ID, REQUESTING_ENGINE_TRANSACTION_ID FROM performance_schema.data_lock_waits;—— 若返回空,不代表没锁争用,可能只是没人正在等待(比如持锁者独占但无并发请求) - 第二步:通过事务 ID 关联持锁细节
用上一步的BLOCKING_ENGINE_TRANSACTION_ID去performance_schema.data_locks查具体锁对象:SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_MODE, LOCK_DATA FROM performance_schema.data_locks WHERE ENGINE_TRANSACTION_ID = ?; - 第三步:定位到会话和 SQL
拿data_locks.THREAD_ID关联performance_schema.threads得PROCESSLIST_ID;再用该THREAD_ID查events_statements_current.SQL_TEXT,若为空,则 fallback 到INFORMATION_SCHEMA.INNODB_TRX.TRX_QUERY
metadata_locks 怎么融入这张“图谱”
元数据锁(MDL)完全独立于 InnoDB 行锁路径,data_locks 和 data_lock_waits 对它不可见。如果你看到 Waiting for table metadata lock 却查不到持锁者,说明你漏了这一层。
-
metadata_locks中LOCK_DURATION = 'TRANSACTION'的记录最危险:事务未提交,锁就一直挂着 - 必须用
OWNER_THREAD_ID关联threads.PROCESSLIST_ID,否则 KILL 会杀错连接 - 常见陷阱:持锁线程在
SHOW PROCESSLIST中显示为Sleep且State为空,但metadata_locks显示LOCK_STATUS = 'GRANTED'—— 这就是“静默持锁”
容易被忽略的采集前提
所有上述查询返回空或数据严重缺失,90% 是因为锁采集根本没开,不是 SQL 写错了。
- 检查
SELECT @@performance_schema;必须为ON - 运行
SELECT * FROM performance_schema.setup_consumers WHERE NAME IN ('global_instrumentation', 'thread_instrumentation');,两行ENABLED都得是YES - 最关键的:执行
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock/innodb%';,所有匹配项的ENABLED列必须是YES;若为NO,仅 SQL 更新无效,需在配置文件加performance-schema-instrument='wait/lock/innodb%=ON'并重启
锁数据不是“实时流”,而是采样快照;data_locks 中的记录可能比事务实际加锁延迟几十毫秒才出现,刚执行完 UPDATE 就查,很可能查不到。











