MySQL调优先别急着改参数 从慢查询到索引落地的实操顺序
先别动配置文件,把慢查询日志打开再说
数据库跑得慢,很多人的第一反应是去翻配置文件,把各种 buffer 数值往上加。我一般不建议这么开局。参数改错了,问题会被掩盖,过几天换个业务高峰又冒出来,而且你根本不知道是哪条 SQL 拖的。
先把慢查询日志打开,阈值从 1 秒起。多数生产库这么一开,会看到大量平时没人注意的语句排着队进来。真正压垮数据库的往往不是那条最复杂的 SQL,而是某条被高频调用的简单查询——它单次只要 30 毫秒,但每秒跑两千次,累积起来的开销远超一条偶尔跑 3 秒的报表语句。
这一步的代价是磁盘 IO 和一点性能损耗,换来的是后续所有优化的依据。没有日志,后面全是猜。
看执行计划,重点盯 type 和 rows 两列
拿到慢查询之后,用 EXPLAIN 看执行计划。字段不少,真正要先看的是两个:type 和 rows。
type 反映访问类型,从好到坏大致是 const、ref、range、index、ALL。看到 ALL 就是全表扫描,这条基本可以确定是问题源头。rows 是预估扫描行数,如果一张几百万行的表预估扫几十万行,而实际只返回几条记录,说明索引没吃上。
还有一种情况容易被忽略:索引建了,但没生效。常见原因是字段上用了函数,比如 WHERE DATE(create_time) = '2026-01-01',这种写法会让索引失效,正确做法是写成范围条件,把函数放到值那一侧。
隐式类型转换也一样。字符串字段用数字去比较,MySQL 会做转换,索引直接作废。这类问题不排查,加再多内存也没用。
索引不是越多越好,这几类才值得建
索引能加快读,代价是拖慢写,还占空间。一张写入频繁的表挂十几个索引,插入性能会明显下滑。我一般按下面这个优先级来补:
- WHERE 条件里出现频率最高的字段,优先做单列或联合索引的前缀
- 联合索引要遵守最左前缀,把区分度高的字段放前面
- ORDER BY 和 GROUP BY 涉及的字段,能进联合索引就一起进,避免额外排序
- 区分度极低的字段(比如性别、状态位只有两三个值)单独建索引意义不大
覆盖索引是性价比很高的一招。如果查询需要的字段全在索引里,数据库不用回表,速度提升往往比调参数明显得多。代价是索引体积变大,写入更慢,所以只对那几条核心查询做覆盖就够了。
索引建完记得用 EXPLAIN 复核一遍,别建完就当完事。
参数只调这几个,其余先放着
参数层面,我认为值得动的其实不多。innodb_buffer_pool_size 是影响最大的一项,通常设成物理内存的 50% 到 70%。一台 64G 内存的机器,这个值给到 40G 左右比较常见。给太小,数据反复从磁盘读;给太大,系统本身和其他进程会缺内存。
连接数也要留意。max_connections 开得过大,每个连接都要占内存,高并发下反而拖垮机器。多数业务把连接数控制在几百以内,配合应用侧连接池复用,比一味调大更稳。
还有一点:连接池的空闲连接回收时间要设得比数据库的 wait_timeout 短,否则应用拿到的是已被服务端断开的连接,报错很难查。
参数调优的空间其实有限。当单表数据量到几千万行,索引也做扎实了,性能还是上不去,那多半不是配置问题,而是单机硬件到顶了。这时候继续抠参数是浪费时间。
什么时候该换机器,而不是继续调
判断标准很直接:CPU 长期打满、磁盘 IO 排队、内存不够导致频繁换页,这三样里中了任何一样,调参已经救不回来。该做的是垂直升级或者读写分离。
垂直升级里,磁盘类型的影响最大。同样的配置,SATA 盘换成 NVMe,随机读写差距是数量级的,对数据库这种小 IO 密集的场景尤其明显。内存和 CPU 反而要排在后面考虑。
如果业务本身是读多写少,加从库做读写分离比堆单机配置更划算。写请求集中到主库,读请求分摊到从库,单机压力立刻降下来。代价是架构复杂了,主从延迟要监控,一致性要求高的查询还得走主库。
带宽这块,数据库服务器一般不是瓶颈,但备份、主从同步会吃带宽。做异地从库的时候,机房之间的线路质量直接影响同步延迟。秀米云这边做数据库主从或者独立部署 MySQL 的话,可以看看 马来西亚服务器1(E3-1230 / 16G / 20M,月付 $99.00),小规模业务起步够用;数据量和并发再往上走,马来西亚服务器3(E5-2698v4*2 / 64G / 20M,月付 $269.00)能给缓冲池留出更宽裕的内存空间。这两款都是独立服务器,IO 和内存不受邻居影响,比共享型的云主机更适合跑数据库。
调优的顺序是先定位、再改 SQL 和索引、最后才动参数和硬件。顺序反了,钱花了问题还在。如果你手上的库已经索引做扎实、慢查询也清干净了,性能还是顶不住,那就不用再纠结配置项了,直接看硬件和架构,该加内存加内存,该上 NVMe 上 NVMe。