必须开启Performance Schema并启用锁相关仪器才能查锁,仅靠PROCESS权限或SHOW OPEN TABLES无效;需检查performance_schema全局变量、调大历史大小、启用wait/lock%仪器并重启mysqld。

查锁必须开Performance Schema
MySQL默认不开启performance_schema的锁相关采集,关着就啥都看不到。不是权限问题,是根本没收集——哪怕你有PROCESS权限也白搭。
确认是否启用:SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'performance_schema'; 返回ON才算基础达标。
但光这个不够,还得确保锁监控开关打开:
-
performance_schema_events_waits_history_long_size建议调大(如10000),否则锁事件可能被轮转丢弃 -
performance_schema_setup_instruments中必须启用wait/lock%类仪器,尤其是wait/lock/metadata/sql/mdl和wait/lock/table/sql/handler - 修改后需重启mysqld,动态SET不生效
直接看哪些表被锁住了
核心查询就是连表performance_schema.data_locks和performance_schema.threads,过滤掉空事务或系统线程。
常用诊断SQL:
SELECT l.OBJECT_SCHEMA, l.OBJECT_NAME, l.LOCK_TYPE, l.LOCK_MODE, l.LOCK_STATUS, t.PROCESSLIST_ID AS PID, t.PROCESSLIST_INFO AS SQL_TEXT FROM performance_schema.data_locks l JOIN performance_schema.threads t ON l.THREAD_ID = t.THREAD_ID WHERE l.LOCK_STATUS = 'GRANTED' OR l.LOCK_STATUS = 'PENDING';
注意点:
-
LOCK_STATUS = 'PENDING'表示正在等锁,对应阻塞源头;'GRANTED'是已持有锁的会话 -
OBJECT_SCHEMA为空时可能是全局锁或DDL锁,别漏掉NULL值 -
PROCESSLIST_INFO可能为NULL(比如后台线程或已断开连接),不能只靠它定位SQL
区分MDL锁和行锁/表锁
同一个data_locks表里混着三类锁:MDL(元数据锁)、InnoDB行锁、InnoDB表级意向锁。混淆它们会导致误判阻塞原因。
快速识别方法:
-
LOCK_TYPE = 'METADATA'→ 全是MDL锁,常见于ALTER TABLE卡住SELECT,或长事务拖着DROP TABLE -
LOCK_TYPE = 'TABLE'+LOCK_MODE含IX/IS→ 意向锁,一般不阻塞,但说明事务开了 -
LOCK_TYPE = 'RECORD'→ 真正的InnoDB行锁,LOCK_DATA字段会显示具体主键值(如123),这才是热点行争用的证据
MDL锁不会出现在information_schema.INNODB_TRX里,只在performance_schema中可见——这点特别容易漏查。
为什么SHOW OPEN TABLES WHERE In_use > 0不管用
这个命令只反映表是否被FLUSH TABLES或LOCK TABLES显式锁住,对InnoDB行锁、MDL锁完全无感。线上真出问题时,它大概率返回空,让人误以为“没锁”。
真正有用的补充手段:
- 查
sys.innodb_lock_waits视图(依赖performance_schema且需sysschema安装)——它把阻塞链做了关联,比手连data_locks更省事 - 看
information_schema.INNODB_TRX里的TRX_STATE = 'LOCK WAIT',配合TRX_MYSQL_THREAD_ID反查PROCESSLIST_ID,可定位等待中的线程 -
SHOW ENGINE INNODB STATUS\G的TRANSACTIONS段落仍有效,但输出是快照、不可过滤,且锁信息格式难解析
实际排查时,data_locks + innodb_trx + processlist 三表关联才是稳解,缺一不可。单靠一个视图容易断链。


















