show open tables 显示表是否被线程缓存打开,in_use=1 不代表锁表;查真实锁需用 performance_schema.data_locks(8.0+)或 information_schema.innodb_trx 等(5.7),mdl 锁须查 metadata_locks。

SHOW OPEN TABLES 显示的是“打开状态”,不是“锁定状态”
很多人执行 SHOW OPEN TABLES 后看到 In_use 列为 1,就以为这张表被锁住了——这是最常见的误解。SHOW OPEN TABLES 只反映表是否被当前线程缓存打开(比如执行过 SELECT 或 UPDATE 后还没释放),和行锁、表锁、MDL 锁完全无关。它不告诉你谁在锁表、为什么锁、锁了多久。
真正想查“正在被锁住的表”,得换思路:
-
SHOW OPEN TABLES WHERE In_use > 0—— 仅表示表句柄被占用,常见于长事务或未关闭的游标,不代表阻塞 - 要定位真实锁冲突,必须看
information_schema.INNODB_TRX、INNODB_LOCKS(MySQL 5.7)或performance_schema.data_locks(MySQL 8.0+) -
SHOW PROCESSLIST配合State列里的Waiting for table metadata lock或Locked才是更直接的线索
查 MySQL 当前真实锁表情况:用 performance_schema(MySQL 8.0+)
MySQL 8.0 默认启用 performance_schema,且 data_locks 表能直接展示每条锁记录的类型、对象、事务 ID 和等待状态。这是目前最准、最轻量的方式。
常用组合查询:
SELECT ENGINE_TRANSACTION_ID AS trx_id, OBJECT_SCHEMA AS db, OBJECT_NAME AS table_name, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks WHERE OBJECT_SCHEMA = 'your_db_name';
注意点:
-
LOCK_STATUS = 'WAITING'表示该事务正被阻塞;'GRANTED'表示已持有锁 -
LOCK_DATA在行锁时显示具体主键值(如123),对排查热点行很有用 - 需确保
performance_schema的相关 instrument 已开启:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl';
MySQL 5.7 怎么查锁表?别依赖 SHOW OPEN TABLES
5.7 没有 data_locks,但还能用老三件套拼出锁视图:information_schema.INNODB_TRX、INNODB_LOCKS(已废弃但默认仍可用)、INNODB_LOCK_WAITS。不过要注意:
-
INNODB_LOCKS在 5.7.30+ 默认关闭(innodb_status_output_locks=OFF),需手动开:SET GLOBAL innodb_status_output_locks = ON; -
INNODB_LOCK_WAITS只显示等待关系(比如 trx_id 123 等待 trx_id 456),不展示锁在哪张表上,必须关联INNODB_TRX和INNODB_LOCKS查 - 执行
SHOW ENGINE INNODB STATUS\G是兜底方案,输出里TRANSACTIONS和LATEST DETECTED DEADLOCK段落含锁细节,但信息杂、难过滤
容易被忽略的元数据锁(MDL)陷阱
很多“锁表现象”其实不是 InnoDB 行锁,而是 MDL(Metadata Lock)——比如 ALTER TABLE 正在执行时,另一个会话连 SELECT 都被卡住,SHOW PROCESSLIST 显示 Waiting for table metadata lock。
这类锁不会出现在 INNODB_TRX 或 data_locks 中,因为它属于 Server 层,不在存储引擎里。排查要点:
- 查
performance_schema.metadata_locks(MySQL 5.7.3+ / 8.0+),过滤LOCK_STATUS = 'PENDING' - 重点看
OWNER_THREAD_ID对应哪个线程,再查performance_schema.threads找 SQL - DDL 操作(尤其是大表
ALTER)会持 MDL 写锁,期间所有对该表的读写都会排队——哪怕只是SELECT COUNT(*)
MDL 锁一旦形成,往往比 InnoDB 锁更隐蔽,也更难通过常规锁视图一眼识别。











