show processlist是轻量起点,但需联合innodb_trx和innodb_lock_waits才能闭环定位阻塞源头:通过innodb_lock_waits查blocking_trx_id,再关联innodb_trx获取线程id,最终映射到processlist中的id。

能直接看到谁卡住了、为什么卡、卡了多久,SHOW PROCESSLIST 是最轻量也最有效的起点;但光看它容易漏掉真正阻塞的源头——得配合 INNODB_TRX 和 INNODB_LOCK_WAITS 才能闭环。
怎么快速揪出正在阻塞别人的 SQL
只用 SHOW PROCESSLIST 很难分辨“谁在等谁”。比如一个线程状态是 Locked 或 Waiting for table metadata lock,它自己没在执行,只是干等,Info 列还是 NULL,根本看不出被谁挡了路。
必须查锁等待关系:
-
SELECT * FROM information_schema.INNODB_LOCK_WAITS;—— 这张表里有BLOCKING_TRX_ID和REQUESTING_TRX_ID,直接告诉你谁在堵谁 - 再连查
INNODB_TRX表,用BLOCKING_TRX_ID找到那个“始作俑者”的TRX_MYSQL_THREAD_ID,就能对应到PROCESSLIST里的Id - 注意:
INNODB_LOCK_WAITS只有真发生锁等待时才有记录,空结果不等于没阻塞(可能是 MDL 锁或未进入 InnoDB 层)
为什么 SHOW FULL PROCESSLIST 有时看不到完整 SQL
不是权限问题,也不是截断逻辑变了,而是 MySQL 默认把 Info 字段限制在 1024 字节。哪怕加了 FULL,超长语句依然会被砍掉——尤其带大 JSON、长子查询或嵌套 CTE 的语句。
更稳的办法是查 performance_schema.events_statements_current:
- 需要先确认已开启:
SELECT * FROM performance_schema.setup_consumers WHERE NAME = 'events_statements_current'; - 然后执行:
SELECT THREAD_ID, SQL_TEXT FROM performance_schema.events_statements_current WHERE SQL_TEXT IS NOT NULL ORDER BY TIMER_START DESC LIMIT 5; - 这个视图里存的是解析后的真实语句,不受 1024 字节限制,但默认只保留每个线程最近一条
State 列里哪些值真正代表阻塞
State 不是越长就越危险,关键看是否处于“等待资源”而非“干活中”:
-
Locked:明确被表级锁或元数据锁(MDL)卡住,常见于ALTER TABLE期间其他 DML 被挂起 -
Waiting for table metadata lock:和上面同源,但更具体,说明正卡在获取 MDL 阶段 -
Sending data或Sorting result持续超过 30 秒:未必是阻塞,但大概率是没走索引或结果集太大,需结合EXPLAIN看执行计划 -
update或delete语句状态变成Updating却长时间不动:可能是被行锁阻塞,此时它不会显示Locked,得靠INNODB_LOCK_WAITS发现
普通用户只能看到自己的会话,怎么办
没有 SUPER 或 PROCESS 权限时,SHOW PROCESSLIST 和 information_schema.PROCESSLIST 都只返回当前用户发起的连接,完全看不到别人在干啥——这会让阻塞排查直接失效。
可行替代方案只有两个:
- 让 DBA 临时授权:
GRANT PROCESS ON *.* TO 'your_user'@'%';(最小权限原则,用完即 revoke) - 改用
performance_schema.threads+events_statements_history_long(如果已开启 long history):普通用户可查自己线程的历史语句,虽不能跨用户,但至少能确认“是不是我写的某条 SQL 正在拖慢全局” - 切记:不要依赖应用层日志来反推数据库阻塞,延迟高、信息残缺、无法关联事务 ID
真正卡住系统的往往不是那条 Time 最长的 SQL,而是它背后持有的锁没释放,导致一串后续请求全在排队。盯住 INNODB_TRX 里的 TRX_STATE = 'RUNNING' 且 TRX_STARTED 时间异常早的事务,比单纯杀 Time > 60 的线程有用得多。











