2026-09-20 15:42 1002 次浏览

MySQL调优别只盯着慢查询:从连接数到内存分配,这几个参数才是瓶颈

很多站长遇到MySQL卡顿就急着加索引、改SQL,却忽略了连接数、缓冲池和临时表这些底层参数。本文从真实排障场景出发,讲清连接数爆满、内存分配失衡、磁盘临时表泛滥三类问题的定位与调优方法。

连接数被打满,先别急着调大max_connections

半夜收到监控告警,数据库连接数跑到1000以上,网站开始报「Too many connections」。很多人的第一反应是把max_connections从500改到2000,结果第二天连接数更高了,服务器负载反而更重。

连接数暴涨通常不是配置太小,而是应用侧没有正确释放连接。先看Threads_connectedThreads_running两个状态值:如果连接数高但running很低,说明大量连接处于Sleep状态,问题在连接池或代码里的长连接没有回收;如果running也高,那才是真正的并发压力。

定位方法很简单,执行SHOW PROCESSLIST看Sleep连接来自哪个应用账号,再结合连接池配置检查空闲回收时间。把连接池的maxIdle和maxActive设合理,比盲目调大数据库上限有用得多。

innodb_buffer_pool_size不是越大越好

缓冲池是InnoDB最核心的内存区域,但把它设成物理内存的80%并不适合所有场景。如果服务器上还跑着Web服务、缓存服务,缓冲池吃光内存会触发系统swap,磁盘IO瞬间飙升,查询延迟反而恶化。

判断缓冲池是否够用,看Innodb_buffer_pool_read_requestsInnodb_buffer_pool_reads的比值。前者是逻辑读,后者是落到磁盘的物理读。如果物理读占比长期高于1%,说明热数据没被缓存住,可以适当加大;如果已经低于0.1%,再加就是浪费内存。

另外,缓冲池的实例数innodb_buffer_pool_instances在高并发下也值得调整。单实例在几十个线程并发时容易产生内部锁竞争,一般建议每1GB缓冲池配一个实例,但不要超过16个。

临时表和排序溢出,才是慢查询的隐形推手

有些SQL单看执行计划没问题,但一到复杂查询就慢,原因往往在磁盘临时表。检查Created_tmp_disk_tablesCreated_tmp_tables的比例,如果磁盘临时表占比超过20%,说明内存临时表装不下中间结果。

可以适当调大tmp_table_sizemax_heap_table_size,两者要设成一样的值才生效。但更根本的解决方式是优化SQL:减少不必要的GROUP BY、避免在WHERE里对字段做函数运算、给排序字段加合适索引。

排序缓冲sort_buffer_size是每个连接独享的,设太大在几百连接下会直接吃光内存。建议从1M~2M起步,结合Sort_merge_passes状态值观察,如果这个值持续增长,说明排序需要多轮归并,再针对性调整。

如果数据库已经压到物理机瓶颈,与其反复调参数,不如把实例迁到内存和IO更充裕的独立服务器上。马来西亚大带宽服务器 II 提供64G内存和100M带宽,适合中大型数据库独立部署,避免和Web服务抢资源。