Sleep状态多不等于数据库卡顿,它仅表示连接空闲等待命令;真正需警惕的是长时间未释放的事务或未加索引的慢查询。

为什么 show processlist 里大量 Sleep 状态不等于数据库卡了
MySQL 的 Sleep 状态表示连接已建立但当前没有执行任何 SQL,它只是空闲等待新命令——这本身是正常现象,尤其在使用连接池(如 HikariCP、Druid)的 Java 应用中。Sleep 连接是否危险,取决于它的持续时间、数量与业务负载的关系。如果 Sleep 连接平均存活数小时且长期不释放,才可能指向连接未正确 close、连接池配置不合理或应用存在连接泄漏。
如何快速判断 Sleep 连接是否异常
直接查 SHOW PROCESSLIST 不够,需结合 Time 列和连接来源分析:
-
Time值大于应用层连接超时(如 Druid 的maxWait或 MySQL 的wait_timeout)仍不退出 → 检查应用是否忘记connection.close()或连接池未启用 testOnBorrow/testWhileIdle - 大量
Sleep来自同一 IP + 同一用户 + 相同程序名(Info为空)→ 很可能是连接池预热后未被复用,或连接池最小空闲数(minIdle)设得过高 -
Sleep连接数持续 > 连接池最大值(maxActive/maximumPoolSize)→ 存在连接未归还,需抓取应用日志中的 JDBC 调用栈
Query 状态长时间不结束才是真问题
Query 状态代表线程正在执行 SQL,此时关注点完全不同:
-
State显示Sending data或Copying to tmp table时间过长 → 检查是否缺少索引、是否扫描全表、是否排序/分组数据量过大 -
State卡在Locked或Waiting for table metadata lock→ 表结构变更(ALTER TABLE)阻塞了查询,或长事务未提交导致 MDL 锁未释放 -
Info字段显示的是SELECT ... FOR UPDATE且Time持续增长 → 检查事务是否遗漏COMMIT或存在跨服务未同步的分布式事务
用 SELECT FROM information_schema.PROCESSLIST 做量化分析
人工看 SHOW PROCESSLIST 容易漏判,建议用 SQL 统计比例:
SELECT COUNT(*) AS total, SUM(IF(COMMAND = 'Sleep', 1, 0)) AS sleep_cnt, SUM(IF(COMMAND = 'Query', 1, 0)) AS query_cnt, ROUND(100 * SUM(IF(COMMAND = 'Sleep', 1, 0)) / COUNT(*), 2) AS sleep_pct FROM information_schema.PROCESSLIST;
再叠加过滤条件定位风险连接:
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 600; -- 空闲超10分钟的连接
注意:information_schema.PROCESSLIST 中的 TIME 是该线程空闲/执行的秒数,不是系统时间戳;且该视图只反映查询发起时刻的快照,高并发下需多次采样比对。
真正要警惕的不是 Sleep 多,而是 Sleep 连接里混着长时间未释放的事务(trx_state = 'ACTIVE'),或者 Query 状态里藏着没加索引的慢查询 —— 这些才是拖垮性能的根因。










