MySQL调优别只盯着慢查询:从连接数到内存分配,这几个参数才是瓶颈
很多站长遇到MySQL卡顿就急着加索引、改SQL,却忽略了连接数、缓冲池和临时表这些底层参数。本文从真实排障场景出发,讲清连接数爆满、内存分配失衡、磁盘临时表泛滥三类问题的定位与调优方法。
连接数被打满,先别急着调大max_connections
半夜收到监控告警,数据库连接数跑到1000以上,网站开始报「Too many connections」。很多人的第一反应是把max_connections从500改到2000,结果第二天连接数更高了,服务器负载反而更重。
连接数暴涨通常不是配置太小,而是应用侧没有正确释放连接。先看Threads_connected和Threads_running两个状态值:如果连接数高但running很低,说明大量连接处于Sleep状态,问题在连接池或代码里的长连接没有回收;如果running也高,那才是真正的并发压力。
定位方法很简单,执行SHOW PROCESSLIST看Sleep连接来自哪个应用账号,再结合连接池配置检查空闲回收时间。把连接池的maxIdle和maxActive设合理,比盲目调大数据库上限有用得多。
innodb_buffer_pool_size不是越大越好
缓冲池是InnoDB最核心的内存区域,但把它设成物理内存的80%并不适合所有场景。如果服务器上还跑着Web服务、缓存服务,缓冲池吃光内存会触发系统swap,磁盘IO瞬间飙升,查询延迟反而恶化。
判断缓冲池是否够用,看Innodb_buffer_pool_read_requests和Innodb_buffer_pool_reads的比值。前者是逻辑读,后者是落到磁盘的物理读。如果物理读占比长期高于1%,说明热数据没被缓存住,可以适当加大;如果已经低于0.1%,再加就是浪费内存。
另外,缓冲池的实例数innodb_buffer_pool_instances在高并发下也值得调整。单实例在几十个线程并发时容易产生内部锁竞争,一般建议每1GB缓冲池配一个实例,但不要超过16个。
临时表和排序溢出,才是慢查询的隐形推手
有些SQL单看执行计划没问题,但一到复杂查询就慢,原因往往在磁盘临时表。检查Created_tmp_disk_tables和Created_tmp_tables的比例,如果磁盘临时表占比超过20%,说明内存临时表装不下中间结果。
可以适当调大tmp_table_size和max_heap_table_size,两者要设成一样的值才生效。但更根本的解决方式是优化SQL:减少不必要的GROUP BY、避免在WHERE里对字段做函数运算、给排序字段加合适索引。
排序缓冲sort_buffer_size是每个连接独享的,设太大在几百连接下会直接吃光内存。建议从1M~2M起步,结合Sort_merge_passes状态值观察,如果这个值持续增长,说明排序需要多轮归并,再针对性调整。
如果数据库已经压到物理机瓶颈,与其反复调参数,不如把实例迁到内存和IO更充裕的独立服务器上。马来西亚大带宽服务器 II 提供64G内存和100M带宽,适合中大型数据库独立部署,避免和Web服务抢资源。