大量Sleep连接本身不直接导致高负载,但反映应用连接池配置不当或未正确复用连接;应查来源、调优wait_timeout等参数并检查连接池配置。

mysqladmin processlist 看到大量 Sleep 连接,真问题还是假象?
大量 Sleep 状态连接本身不直接导致 CPU 或 I/O 负载高,但往往是应用未正确复用连接、连接池配置不当的信号。重点不是杀掉它们,而是查清谁建的、为什么不释放。
- 先执行
mysqladmin -u root -p processlist | grep -E "(Sleep|Command)",关注Time列——超过 60 秒的Sleep才值得深挖 - 结合
SHOW PROCESSLIST查Host和db字段,快速定位是哪个应用服务、哪个库在持续建连接 - 检查应用侧连接池配置:
maxIdle、minIdle、maxWait(如 HikariCP)是否合理;PHP 的mysqli若没设MYSQLI_OPT_CONNECT_TIMEOUT,可能卡在 DNS 解析上伪装成Sleep -
wait_timeout和interactive_timeout值过大(比如设成 28800),会让空闲连接滞留太久,加重连接数压力,建议调至 300–600
慢查询日志开了但 mysqld 进程依然吃满 CPU,怎么办?
慢查询日志只记录“执行时间长”的语句,但 CPU 高往往来自高频小查询、全表扫描或锁等待——这些可能根本进不了慢日志,因为单次执行没超阈值。
- 确认日志确实生效:
SELECT @@slow_query_log, @@long_query_time, @@log_queries_not_using_indexes;;long_query_time设为 0 可捕获所有查询(仅调试用,线上慎开) - 更有效的是用
pt-query-digest分析日志:pt-query-digest /var/lib/mysql/slow.log --limit 10,它能聚合相似 SQL、统计出现频次,比肉眼扫快得多 - 若日志几乎为空但负载高,立刻看
SHOW ENGINE INNODB STATUS\G中的SEMAPHORES和TRANSACTIONS部分——有大量os_waits或事务卡在LOCK WAIT,说明是锁争用,不是 SQL 慢 - 注意:开启
log_queries_not_using_indexes在高并发下会显著拖慢性能,它强制每条没走索引的查询都写盘,别长期开着
用 EXPLAIN 看执行计划,但 type=ALL 和 rows 很大却没加索引?
不是所有 ALL 都要加索引。MySQL 优化器会权衡:当表小、或 WHERE 条件过滤性极差时,全表扫描反而比索引回表更快。关键看实际 rows 是否远超结果集数量。
- 对
EXPLAIN结果,优先盯key(是否用了索引)、rows(预估扫描行数)、Extra(尤其Using filesort、Using temporary) - 如果
rows是 10 万但只返回 5 行,且Extra有Using where; Using filesort,大概率需要联合索引覆盖WHERE + ORDER BY字段 - 避免在索引字段上用函数:
WHERE YEAR(create_time) = 2024会让索引失效,改用create_time BETWEEN '2024-01-01' AND '2024-12-31' - 注意字符集隐式转换:当
utf8mb4列和utf8参数比较时,索引失效,错误信息里不会报,但EXPLAIN显示key=NULL
查出慢 SQL 了,但 ALTER TABLE 加索引卡住,不敢在线操作?
MySQL 5.6+ 的 ALGORITHM=INPLACE 并非完全无锁,DML 仍可能被阻塞,尤其大表。盲目加索引可能让负载雪上加霜。
- 先用
pt-online-schema-change(推荐)或gh-ost,它们通过影子表+触发器渐进同步,业务零感知,但要求主键存在、不能有外键 - 若必须用原生命令,加
ALGORITHM=INPLACE, LOCK=NONE,但得确认 MySQL 版本支持(5.6+ 对某些 DDL 仍需短暂锁表) - 加索引前,用
SELECT COUNT(*)和SHOW TABLE STATUS看表大小;千万级以下可直接操作,亿级务必走工具 - 别在高峰期做 DDL;监控
Threads_running和Innodb_row_lock_waits,若锁等待飙升,立即中止
真正难的不是找到哪条 SQL 慢,而是判断它慢是因为数据量、索引缺失、还是锁住了别人;日志和命令只是镜子,照见的是应用逻辑和数据库配置的耦合细节。










