MySQL调优别急着改参数,先把这三件事理清楚
数据库跑着跑着开始变慢,第一反应往往是去翻 my.cnf,看到 innodb_buffer_pool_size 就往上调。这么干有时候有效,更多时候是把内存吃光然后开始 swap,机器比之前还卡。调优这件事的麻烦在于,同一个现象背后可能是 SQL 写法的问题,也可能是磁盘扛不住,还可能是连接数配得离谱。方向找错了,参数改得再勤也没用。
我一般会按一个固定顺序往下走:先看清楚慢在哪,再判断能不能靠改 SQL 解决,改不动了才动参数,最后才考虑加硬件。顺序反了,钱花出去效果不一定有。下面按这个顺序说。
先搞清楚慢的是查询还是写入
打开慢查询日志是最省事的一步。long_query_time 设成 1 秒,跑一天,看看有多少条。如果一天只有几十条,问题可能不在 SQL,而在某个高峰时段的并发;如果一天几万条,那就是查询本身写得有问题。
另一个要看的指标是 InnoDB 的读写比。用 SHOW GLOBAL STATUS 看 Com_select 和 Com_insert/Com_update 的比例。读多写少的库,优化重点在索引和缓冲池;写多的库,瓶颈通常在磁盘的 fsync 上,这时候加内存帮助有限。
还有一个容易被忽略的点:连接数。max_connections 设成 1000 但实际峰值只有 80,多出来的只是内存开销。反过来,如果 Threads_connected 长期贴着上限,应用侧报「too many connections」,那就得先解决连接池配置,而不是去调数据库。
索引能解决八成的慢查询,但别乱加
我见过不少库,表上十几个索引,写入慢得离谱。索引不是越多越好,每个索引都要在写入时维护。判断一条慢 SQL 该不该加索引,先用 EXPLAIN 看 type 和 rows。type 是 ALL 说明全表扫,rows 接近表总行数,那基本就是缺索引。
加索引有个原则:把 WHERE 里等值条件放前面,范围条件放后面。比如 WHERE status = 1 AND created_at > '2026-01-01',联合索引应该是 (status, created_at),反过来效果会差很多。
- 区分度低的字段(比如性别、状态只有两三个值)单独建索引意义不大
- 联合索引要遵守最左前缀,跳着用等于没建
- ORDER BY 和 GROUP BY 的字段尽量纳入同一个索引,避免 filesort
如果一条 SQL 改完索引还是慢,先看是不是返回了大量不需要的列。SELECT * 在宽表上是真费劲,尤其是带 TEXT 字段的表。把列收窄,网络传输和临时表开销都能降下来。
参数只动这几个,其余别碰
参数调优我一般只关注三四个值。innodb_buffer_pool_size 是最值得动的,通常设成物理内存的 50% 到 70%。一台 8GB 内存的机器跑 MySQL,缓冲池给 4GB 到 5GB 比较稳,留出空间给操作系统和其他进程。给到 7GB 反而容易触发 OOM。
innodb_log_file_size 影响写入性能,太小会导致频繁 checkpoint。多数情况下设成 256MB 到 1GB 之间。改这个值需要重启,而且旧日志文件要清掉,操作前先备份。
max_connections 按实际并发设,配合应用侧的连接池上限,不要两边都放开。sort_buffer_size 和 join_buffer_size 是连接级参数,设太大会在并发高时把内存吃光,默认值通常够用。
调完参数别急着上线,用 sysbench 或真实流量回放跑一轮,对比改前改后的 QPS 和 P95 延迟。没有对比数据的调优,等于凭感觉。
什么时候该考虑换机器
如果 SQL 已经优化过,索引也合理,参数也调到位,延迟还是下不来,那大概率是硬件到顶了。这时候看两个指标:磁盘 IOPS 和 CPU 的 iowait。iowait 长期超过 20%,说明磁盘是瓶颈,换 NVMe SSD 比加内存有用。
数据库对磁盘的要求比一般应用高,尤其是写入密集的场景。如果业务本身需要独立的大内存和稳定 IO,用独立服务器会比共享资源的方案可控得多。马来西亚机房那边有配 AMD EPYC 7542 双路、128G 内存的机型,跑中等规模的 MySQL 实例比较从容,具体配置可以看 马来西亚服务器6。预算紧一些的话,E5-2698v4 双路加 64G 的配置也能撑住多数中小业务,参考 马来西亚服务器3。
判断标准很直接:如果你的库数据量在几十 GB 以内,QPS 不超过几千,优化 SQL 和索引基本就够,没必要上高配。数据量上百 GB、写入频繁、又要保证低延迟,那硬件投入是绕不过去的。先花一周把慢查询清干净,再决定要不要换机器,这个顺序别颠倒。