MySQL调优别急着改参数,先把这三笔账算清楚

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

数据库变慢这件事,很多人的第一反应是打开my.cnf改参数。我见过不少站长把innodb_buffer_pool_size从128M调到4G,重启完发现查询还是慢。问题不在参数上——一条没走索引的SQL,buffer pool给到64G也救不回来。调优的顺序应该是先定位、再改结构、最后才动配置,跳过前两步直接改参数,等于蒙着眼睛修车。

先看慢在哪:慢查询日志比参数表有用

调优的第一步不是改,是看。MySQL默认的long_query_time是10秒,这个阈值太宽了,很多拖慢页面的查询在0.5秒到2秒之间,根本进不了慢日志。

我一般会先把阈值降到0.5秒,跑一天业务,再回头看日志里排前面的那几条。通常一个站点的慢查询里,八成以上的耗时集中在少数几条SQL上,把它们拎出来,问题就清楚了一半。

拿到慢SQL之后用EXPLAIN看执行计划。重点看三列:type是不是ALL或者index(全表扫描和全索引扫描都要警惕)、rows扫描行数是不是远超返回行数、Extra里有没有出现Using filesort或Using temporary。这三样只要中一个,基本就是索引没建对。

  • type为ALL:表上没有可用索引,或者条件字段没走索引。
  • Extra出现Using filesort:排序字段没进索引,数据量大时开销翻倍。
  • rows远大于实际返回行数:索引选择性差,比如在性别这种低基数字段上建索引。

这一步的代价是花时间看日志,但省下的是后面反复试参数的时间。参数改错了要重启,重启就有停机窗口,这笔账不难算。

索引和SQL结构:能在这里解决的不要留到参数层

定位到问题SQL之后,优先动索引。联合索引的顺序按「等值条件在前、范围条件在后」排,这条规则能解决大部分回表问题。比如WHERE status=1 AND created_at > '2026-01-01',索引建成(status, created_at)比反过来有效得多。

另一类常见问题是分页。LIMIT 100000, 20这种写法会先扫过前十万行再丢掉,越翻到后面越慢。改成基于游标的分页——记住上一页最后一条的id,用WHERE id > 上页末尾id LIMIT 20——扫描行数直接降到20行。这个改动不需要加硬件,改一条SQL就见效。

还有一种情况是单表数据涨到千万级,索引也建对了,查询还是慢。这时候要考虑的是拆表还是归档。冷数据挪到历史表,主表保持在几百万行以内,查询和写入都会轻快很多。我倾向于先归档再考虑分库分表,分库分表带来的运维复杂度,比归档高一个量级。

索引建得越多,写入越慢,这点也要权衡。一张表上挂七八个索引,每次INSERT都要更新所有索引页,写入密集的业务会明显感到吃力。通常一张表的索引控制在五个以内比较稳妥,具体还是看读写比例。

参数层怎么调:buffer pool给多少,连接数卡在哪

结构和SQL都理顺之后,再回头动参数。innodb_buffer_pool_size是最值得调的一项,它决定InnoDB能缓存多少数据和索引页在内存里。经验值是按可用内存的50%到70%给,前提是这台机器只跑MySQL。

如果服务器上还跑着Web服务或者Redis,那这个比例要往下压。一台16G内存的机器,如果Web和数据库混部,buffer pool给到8G左右比较稳,留出内存给系统缓存和连接开销。给太多反而会触发swap,性能断崖式下跌。

连接数这块,max_connections设成几千是常见误区。每个连接都要占内存,几千个空闲连接会把内存吃光。真实的并发连接数通常远低于这个数字,用SHOW STATUS LIKE 'Threads_connected'看当前值,再留两三倍余量就够了。连接开得过多,上下文切换的开销也会拖慢响应。

如果调完参数、优化完SQL,数据库还是扛不住,那就是硬件层面的事了。这时候得看是内存不够、还是磁盘IO到顶。SSD和机械盘在随机读写上的差距是数量级的,数据库跑在机械盘上,再怎么调参数也补不回来。

把数据库从混部环境里拆出来单独放一台,是很多中小站点性能提升最直接的一步。秀米云有马来西亚机房的独立服务器,比如马来西亚裸机云 XIII,E5-2698v4双路配64G内存,跑单实例MySQL内存给得开,20M带宽对数据库这种小包往返的流量也够用。数据库和Web分开之后,两边的资源互不挤占,调优的空间才真正打开。

调优的终点不是把参数调到极致,而是让瓶颈清楚地暴露出来。先看慢日志定位SQL,再改索引和分页写法,最后按内存和并发量调buffer pool与连接数。这套顺序走下来,多数中小站点的数据库都能回到正常水位。如果三步都做完还是慢,别继续在参数里找答案,该考虑的是加内存或者换SSD了。