MySQL 调优别急着改参数,先看清这三笔账
数据库变慢的时候,很多人的第一反应是登录服务器改 my.cnf,把 buffer pool 调大、把连接数拉高,重启一遍再看。结果往往是头两天快了一点,一周后又回到老样子。我在实际排查里遇到的慢库,绝大多数问题不在参数,而在 SQL 和索引本身——参数只是把症状往后推了推。下面按排查顺序讲,先看什么、后动什么,以及钱该花在哪。
先看慢查询日志,别凭感觉猜
没有慢查询日志的调优都是瞎调。先把 slow_query_log 打开,long_query_time 设成 1 秒,跑一天再看。很多库打开之后才发现,真正拖后腿的就是那么两三条 SQL,反复执行几万次。
看日志的时候重点抓两类:扫描行数远大于返回行数的,和排序用到了磁盘临时表的。前者说明索引没走对,后者说明排序字段上缺索引,或者 sort_buffer_size 太小。这两类问题加起来通常能占到慢查询总量的八成以上。
- Rows_examined 是 Rows_sent 的几十倍:索引问题,优先处理
- 出现 Using filesort 或 Using temporary:排序或分组字段需要补索引
这一步不花钱,只花时间,但它决定了后面所有动作的方向。跳过它直接改参数,等于蒙着眼睛修车。
索引是收益最高的一笔投入
一条 SQL 从全表扫描改成走索引,耗时经常从几百毫秒掉到几毫秒,这个提升幅度是调参数永远给不了的。代价是写入会变慢一点,每多一个索引,INSERT 和 UPDATE 都要多维护一棵 B+ 树。所以索引不是越多越好,是按查询来配。
联合索引的字段顺序很关键。等值条件放前面,范围条件放后面,这条规则能解决大部分组合查询。如果一条 SQL 里既有 WHERE 又有 ORDER BY,把排序字段接在等值条件后面,通常能同时消掉 filesort。
另一个常见坑是隐式类型转换。字段是 varchar,查询里传了数字,索引直接失效,这种问题在日志里表现为扫描行数突然暴涨。类似的情况还有在索引列上套函数、用 LIKE '%xxx' 左模糊匹配。改 SQL 比加索引便宜,能改 SQL 就先改 SQL。
索引建好之后,如果单机确实扛不住了,再考虑往上加配置。秀米云这边的 马来西亚服务器6 是 AMD EPYC 7542 双路 32 核、128G 内存、20M 带宽,月付 $719,跑中大型 MySQL 实例比较合适——内存大意味着 InnoDB buffer pool 能开得更大,热点数据基本可以全部缓存在内存里,磁盘 IO 压力会小很多。预算紧一些的话,马来西亚服务器4 是 Gold-6133 双路、64G 内存、20M 带宽,月付 $319,适合日活几万级别的业务。
参数只调这几个,其余保持默认
参数分两类:一类是跟着硬件走的,一类是跟着业务走的。硬件类的就那么几个,改完基本不用再动。
innodb_buffer_pool_size 是最值得调的一个,通常设成物理内存的 50% 到 70%。一台 64G 的机器开到 40G 左右比较稳,剩下的留给连接和操作系统。这个值改大之后,读操作基本走内存,磁盘只负责落盘。
innodb_log_file_size 影响写性能,太小会导致频繁刷盘。设成 1G 到 2G 之间比较常见,代价是崩溃恢复时间会变长。这点需要权衡:能接受恢复慢一点,就换写入吞吐。
连接数相关的 max_connections 不要盲目往大调。每个连接都要占内存,开太大反而会触发 swap,整机一起变慢。真正该做的是在应用层加连接池,把并发压下来。
还有一类参数是给特定场景用的,比如大批量导入时临时关掉唯一性检查,或者把事务隔离级别从 RR 降到 RC 来减少间隙锁。这些属于按需调整,改完记得改回去。
什么时候该加机器,什么时候不该
加内存能救的是热数据装不下、buffer pool 频繁换页的库。加 CPU 能救的是并发连接多、排序计算量大的库。但如果瓶颈在磁盘随机 IO,加 CPU 和内存都没用,得换 SSD 或者做分库分表。
我的判断顺序是:先看慢查询日志定位 SQL,再补索引和改写法,索引实在优化不动了才动参数,参数调完还压不住再考虑加配置或者拆库。反过来做,钱花得最快,效果来得最慢。
单表超过两千万行、写入量又持续增长的时候,再怎么调单机都会到天花板,这时候分库分表或者读写分离才是正解。调优解决的是「本来能跑快但没跑快」的问题,解决不了数据量本身超载的问题。