真卡死需看TIME是否超预期、STATE是否为高风险状态、INFO是否含大范围未索引操作;KILL CONNECTION才能释放锁,KILL QUERY无效;批量终止须过滤系统用户、只读查询、设时间阈值并避开FOR UPDATE语句。

怎么一眼识别真卡死,而不是假忙
别只盯着 SHOW PROCESSLIST 里 State 是 Query 就动手。很多“看起来在跑”的线程其实卡在锁、元数据等待或网络收发上,真正要盯的是三件事:
— TIME 字段是否远超业务预期(比如 >300 秒);
— STATE 是 Waiting for table metadata lock、Sending data 或 Copying to tmp table 这类高风险状态;
— INFO 截断后仍能看出是大范围 UPDATE、DELETE 或没走索引的 JOIN。
用 SHOW FULL PROCESSLIST 才能看到完整 SQL,否则前 100 字符可能只显示 SELECT * FROM orders WHE...,根本没法判断是不是扫全表。
KILL QUERY 和 KILL CONNECTION 到底该选哪个
选错命令等于白干:
— KILL QUERY <code>id 只停当前语句,连接还活着,事务没提交也没回滚,锁照常持有——对死锁、MDL 锁、长事务卡住完全无效;
— KILL CONNECTION <code>id(MySQL 5.7+ 推荐写法,等价于旧版 KILL <code>id)才会断开 TCP 连接,强制触发事务回滚并释放所有锁。
实操建议:
— 先试 KILL QUERY <code>id,3 秒内 STATE 没变回 Sleep,立刻升级为 KILL CONNECTION <code>id;
— 如果线程 STATE 已是 Locked 或 Waiting for table metadata lock,跳过 KILL QUERY,直接 KILL CONNECTION <code>id;
— 别杀 User = 'system_user' 或 User = 'event_scheduler' 的线程,复制和定时任务会中断。
批量终止前必须加的过滤条件
手写 KILL 容易看串行、杀错人。安全做法是先生成语句再人工核对:
— 排除系统用户:USER NOT IN ('root', 'system_user', 'mysql.infoschema');
— 排除只读查询(一般不持锁):COMMAND = 'Query' AND STATE = 'Executing';
— 设时间阈值(别一刀切):TIME > 600(10 分钟)比 > 60 更稳妥,避免误杀报表导出类合理长任务;
— 加上 AND INFO NOT LIKE '%SELECT%FOR UPDATE%' 可避开显式加锁的业务关键语句。
示例语句:
SELECT CONCAT('KILL CONNECTION ', id, ';') FROM information_schema.PROCESSLIST WHERE COMMAND = 'Query' AND STATE = 'Executing' AND TIME > 600 AND USER NOT IN ('root', 'system_user');执行结果复制进客户端,逐条确认再运行。
杀完之后最容易被忽略的两件事
命令敲完不是结束:
— 立刻查 INFORMATION_SCHEMA.INNODB_TRX,确认对应 TRX_MYSQL_THREAD_ID 是否消失;如果还在且 TRX_STATE = 'ROLLING BACK',说明回滚中,得等——大事务回滚可能比执行还慢;
— 跑 SHOW ENGINE INNODB STATUS\G,重点看 TRANSACTIONS 部分有没有残留锁、有没有 ROLLING BACK 进度条;
— 别只看 PROCESSLIST 里 ID 消失了就放心,线程 ID 会被复用,真正要看的是事务是否清空、锁是否释放。回滚没完成时,后续 ALTER TABLE 或 TRUNCATE 仍可能被阻塞。


















