MySQL调优别乱改参数,先把慢查询和索引搞明白

2026-10-04 14:24 1004 次浏览

数据库跑得慢,多数人第一反应是去翻my.cnf,把能改的参数全改一遍。改完重启,发现该慢的还是慢。问题在于方向反了——参数调优是在查询和索引都理顺之后才做的事,顺序颠倒过来,改再多参数也是白费。这篇按实际动手顺序讲:先看慢查询日志定位问题SQL,再分析执行计划决定加不加索引,最后才轮到内存和连接数这类参数。每一步都有具体的判断标准,不是泛泛而谈。

慢查询日志不开,等于闭着眼睛调

MySQL默认是不记录慢查询的,很多人调优第一步就卡在这。先把开关打开,设置一个阈值,比如long_query_time=1,意思是执行超过1秒的SQL都记下来。

开启方式有两种,临时生效的可以直接在会话里执行set global slow_query_log=1,重启就没了。要长期生效就写进配置文件,加两行:slow_query_log=1和slow_query_log_file=/var/log/mysql/slow.log。日志路径要确保MySQL进程有写权限,不然开了也是空的。

阈值定多少合适?我一般先设1秒跑一天,看看日志量。如果一天下来几百条,说明问题比较集中,直接挑执行时间最长的几条开刀。如果日志刷得飞快,说明阈值太松,调到2秒或3秒再看。别一上来就设0.1秒,日志能把磁盘写满,排查起来反而没重点。

拿到慢查询之后,用mysqldumpslow或者pt-query-digest做个汇总,按总耗时排序。总耗时高的SQL才是真正拖慢系统的,单次慢但一天只跑一次的不急。

执行计划里三个字段,决定索引加不加

找到问题SQL,下一步是explain。输出结果字段不少,实际要盯的主要是三个:type、key、rows。

type这一列,看到ALL就是全表扫描,数据量一大必慢。理想情况是ref或者range,等值查询走ref,范围查询走range。看到index也不一定是好事,那是扫了整个索引树,跟全表扫差别不大。

key显示实际用了哪个索引。如果是NULL,说明没走索引,这时候才需要考虑加。rows是预估扫描行数,这个数字跟表总行数越接近,索引效果越差。

加索引有个常见误区:where条件里的字段就无脑加。实际上联合索引的顺序很关键,把区分度高的字段放前面。比如用户表按status和created_at查,status只有几个值,区分度低,放前面效果不好,created_at放前面更合适。具体怎么排,得看实际数据分布,没有万能公式。

还有一种情况是索引建了但没用上。常见原因是字段类型不匹配,比如字符串字段用数字去查,或者对索引字段做了函数运算,像where date(created_at)='2026-01-01'这种写法,索引直接失效,改成范围查询才行。

内存参数给多少,看数据量和并发

查询和索引都处理完,才轮到参数。innodb_buffer_pool_size是影响最大的一个,它决定InnoDB能缓存多少数据和索引在内存里。

设太小,数据频繁从磁盘读,查询自然慢。设太大,把系统内存吃光,可能触发OOM。经验值是给物理内存的50%到70%,但这是有前提的——服务器是MySQL独占。如果上面还跑着别的服务,得先扣掉那部分。

举个例子,16G内存的机器,MySQL独占的话可以给到10G到11G。如果库本身只有2G数据,给10G就是浪费,给4G就够了。反过来,库有30G数据,内存只有16G,那给到11G也只能缓存三分之一,剩下的还得读磁盘。这种情况下加内存比调参数有用。

连接数max_connections也别乱调。默认151,有人直接改成1000,结果每个连接都占内存,并发一上来反而更慢。实际并发多少,看show status里的Threads_connected峰值,按峰值的1.5倍设置比较稳。

调完参数记得观察一段时间,用show global status看Innodb_buffer_pool_read_requests和Innodb_buffer_pool_reads的比值,前者远大于后者说明缓存命中率高,参数给得合理。

收尾:按这个顺序走,别跳步

调优的顺序是先慢查询、再执行计划、最后参数,跳步容易白忙。慢查询日志开起来,阈值从1秒起步;explain看type和key,全表扫描才考虑加索引;buffer pool按内存的50%到70%给,但要结合数据量判断。

如果库不大、查询也简单,可能压根不需要动参数,加个索引就解决了。反过来,数据量到了几十G,内存又只有8G,那再怎么调参数也追不上,该升级配置就升级。判断标准很简单:慢查询日志里还有大量全表扫描,先补索引;索引都补完了还是慢,再看内存够不够。