为什么 SELECT
在高并发下突然变慢?先看真实瓶颈点
不是所有“慢查询”都该优化 SQL,高并发下
SELECT延迟飙升,大概率卡在锁、IO 或连接争用上。比如:大量短连接反复建连耗尽
wait_timeout资源;或二级索引 +
WHERE条件触发间隙锁,导致后续查询被阻塞;又或者
innodb_buffer_pool_size设置过小,频繁刷脏页+磁盘随机读。
EXPLAIN
看不准延迟?必须补上 SHOW PROFILE
和 sys.schema_table_statistics
EXPLAIN只反映执行计划,不体现真实 IO 和锁等待。高并发场景下更需定位“谁在等什么”: 用
SHOW PROFILE FOR QUERY N查看单次查询各阶段耗时(重点关注
Waiting for table metadata lock、
Sending data、
Creating sort index) 查
sys.schema_table_statistics找出物理读最多的表:
SELECT * FROM sys.schema_table_statistics WHERE total_latency LIKE '%s%' ORDER BY io_read_latency DESC LIMIT 5确认是否命中缓冲池:
SELECT (1 - (innodb_buffer_pool_reads / innodb_buffer_pool_read_requests)) * 100 AS hit_rate FROM information_schema.GLOBAL_STATUS WHERE variable_name IN ('innodb_buffer_pool_reads', 'innodb_buffer_pool_read_requests')
加索引反而更慢?注意 WHERE
条件顺序和 IN
列表长度
复合索引失效常发生在高并发写入后统计信息未更新,或
IN子句超过 MySQL 优化器阈值(默认约 300 项),导致放弃使用索引走全表扫描: 用
ANALYZE TABLE强制刷新统计信息(尤其在大批量
INSERT/DELETE后) 避免
WHERE a = ? AND b IN (?, ?, ..., ?)中
b的
IN列表超 200 项;拆成多个查询或改用临时表
JOIN索引字段顺序要匹配最常用过滤组合,例如高频查
status = 'active' AND created_at > '2024-01-01',就建
INDEX(status, created_at),而非反过来
连接池配多大才不拖垮 MySQL?关键看 max_connections
和 wait_timeout
协同
应用层连接池(如 HikariCP)设 100,但 MySQL
max_connections=151默认值极易打满,且空闲连接不及时释放会持续占用内存和锁资源: 先调高
max_connections(建议按峰值 QPS × 平均查询耗时 × 1.5 估算,但不超过 OS 文件描述符限制) 把
wait_timeout从默认 28800(8 小时)降到 60–300 秒,配合连接池的
idleTimeout使用 禁止应用代码中手动
CONNECTION.close()后再复用,MySQL 不支持连接重用,必须由连接池管理生命周期
真正难的是锁竞争与缓冲区争用,这两个问题不会因为加了索引或调了连接数就自动消失——它们藏在慢日志的
Rows_examined和
InnoDB_row_lock_waits指标背后,得盯着看。
