先确认 slow_query_log 是否开启及 long_query_time 设置是否合理,再检查 log_output 类型与存储路径权限;接着用 explain 分析执行计划,关注 type、possible_keys、rows 等关键字段;然后通过 show processlist 和 performance_schema 定位锁等待与高耗时连接;最后排查应用层连接池泄漏。

查不到慢查询日志?先确认 MySQL 的 slow_query_log 是否真开着
很多团队以为开了慢查日志就万事大吉,结果发现 slow_query_log 是 OFF,或者 long_query_time 设成了 10 秒——而实际业务里 500ms 就算卡顿。更隐蔽的是,log_output 被设成 FILE,但磁盘满了或权限不对,日志根本没写进去。
- 用
SHOW VARIABLES LIKE 'slow_query_log'和SHOW VARIABLES LIKE 'long_query_time'确认真实值 - 执行一条已知慢的关联 SQL,立刻查
SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 1(如果log_output = 'TABLE') - 若仍无记录,临时切到
FILE模式,并用tail -f /var/lib/mysql/localhost-slow.log实时观察
EXPLAIN 显示 type=ALL 或 rows 过大?重点看驱动表和索引覆盖
关联变慢,90% 源于驱动表选错或缺失连接字段索引。比如 SELECT * FROM orders o JOIN users u ON o.user_id = u.id,如果 orders.user_id 没索引,MySQL 可能对每条 orders 记录都全表扫描 users 表。
- 用
EXPLAIN FORMAT=TRADITIONAL看type列:出现ALL或index(非唯一索引全扫)就是危险信号 - 检查
possible_keys和key是否为空或未命中预期索引;rows值是否远超实际匹配行数 - 对多表 JOIN,MySQL 默认用小结果集做驱动表,但统计信息过期会导致误判——运行
ANALYZE TABLE orders, users更新统计
show processlist 里一堆 State=Sending data 或 Waiting for table metadata lock?锁和并发正在打架
Sending data 看似正常,实则可能是大结果集传输卡在网卡或客户端缓冲区;而 Waiting for table metadata lock 往往是 DDL(如 ALTER TABLE)被长事务阻塞,连带把所有关联查询堵死。
- 执行
SHOW PROCESSLIST,重点关注Time> 60 且State非Query的连接;用SELECT * FROM information_schema.PROCESSLIST WHERE TIME > 60筛更准 - 查锁等待链:
SELECT * FROM performance_schema.data_lock_waits(MySQL 8.0+),或SELECT * FROM information_schema.INNODB_TRX+INNODB_LOCKS(5.7) - 别只杀
Sleep连接——那些是空闲连接池里的“尸体”,真正该杀的是State=Updating卡住 300 秒的更新事务
连接数爆了但 show variables like 'max_connections' 没超?留意应用层连接池泄漏
max_connections 是 MySQL 层上限,但应用端连接池(如 HikariCP 的 maximumPoolSize)配置不当,会反复建连不释放。现象是 Threads_connected 持续接近上限,且新查询直接报 Too many connections。
- 对比
SHOW STATUS LIKE 'Threads_connected'和应用监控里的活跃连接数,差值大说明连接没归还给池 - 检查应用日志是否有
Connection leak detection警告(HikariCP 默认开启) - 关键参数:HikariCP 的
connection-timeout(别设太小导致重试风暴)、leak-detection-threshold(建议设 60000 ms)
真正卡住生产环境的,往往不是单条 SQL 写得烂,而是慢查询 + 锁等待 + 连接池泄漏三者叠加。一旦看到 Waiting for table metadata lock 和高 Threads_connected 同时出现,优先查有没有人在跑 ALTER TABLE 或 DROP INDEX——这种操作在大表上可能锁表几分钟,所有关联查询全排队。










