应使用show full processlist查看完整sql,并配合information_schema.processlist过滤command='query'、state='executing'且time>300的活跃慢查询,同时排除system_user等系统线程。

查进程时别只看 SHOW PROCESSLIST,要加 FULL 和过滤条件
单纯执行 SHOW PROCESSLIST 很容易漏掉真正卡死的查询——它默认截断 Info 字段(最多 100 字符),且不显示超长运行时间。比如一个执行了 1800 秒的 SELECT ... JOIN ... GROUP BY 可能只显示 SELECT * FROM orders WHE...,根本看不出完整语义。
正确做法是:
- 用
SHOW FULL PROCESSLIST看完整 SQL 文本 - 加 WHERE 过滤:
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND = 'Query' AND STATE = 'Executing' AND TIME > 300;(查运行超 5 分钟的) - 注意排除
User = 'system_user'或User = 'event_scheduler',这些是系统内部线程,杀错会引发复制中断或定时任务失效
KILL QUERY 和 KILL CONNECTION 到底该用哪个?
MySQL 5.7.6+ 支持两个细粒度命令,不是所有场景都适合直接 KILL 1234:
-
KILL QUERY 1234:只终止该连接当前正在跑的 SQL,连接本身保持活跃(Command变成Sleep),适合你只想打断一个慢 SELECT,但还想让应用复用这个连接 -
KILL CONNECTION 1234:连带关闭整个 TCP 连接,客户端会收到Lost connection to MySQL server during query,适合连接本身已卡死(比如处于Waiting for table metadata lock状态无法响应 KILL QUERY) - 如果
KILL QUERY执行后,STATE在几秒内没变回Sleep,立刻升级为KILL CONNECTION
批量终止时别手写 KILL,用 CONCAT 生成安全脚本
手动一个一个 KILL 容易眼花看错 ID,也难保证原子性。更稳妥的方式是先生成语句,再审阅执行:
SELECT CONCAT('KILL QUERY ', id, ';')
FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Query'
AND STATE = 'Executing'
AND TIME > 600
AND USER NOT IN ('root', 'system_user');
把结果复制进客户端执行。注意两点:
- 别在生产环境直接
INTO OUTFILE后SOURCE,文件路径权限和 SELinux 可能拦截 - 务必排除
root用户——DBA 自己跑的维护脚本也可能被误杀
杀完别就走,立刻检查 InnoDB 状态和锁残留
被 KILL 的查询不一定“干净退出”。InnoDB 可能还留着未释放的行锁、间隙锁,甚至事务处于 ROLLING BACK 状态(尤其大事务回滚极慢)。
执行完 KILL 后必须马上确认:
-
SHOW ENGINE INNODB STATUS\G查TRANSACTIONS部分,看是否有TRX_STATE = RUNNING但TRX_ROWS_LOCKED > 0的事务 -
SELECT * FROM performance_schema.data_locks;(MySQL 8.0+)或information_schema.INNODB_TRX+INNODB_LOCK_WAITS查锁等待链 - 如果发现长时间
ROLLING BACK,不要重复KILL——它已经在线程里了,再杀只是重置计时器
真正棘手的是那种 STATE = 'killed' 却一直不消失的进程,大概率是磁盘 I/O 卡住或内核态阻塞,这时只能等它自己恢复或重启 mysqld ——但重启前务必确认 error log 末尾没有 signal 11 或 OS error 5,否则可能掩盖底层故障。











