聊MySQL性能优化,很多人第一反应就是加索引、调参数。但真正干过几年DBA或者后端开发的人都知道,这事儿没那么简单。一个查询慢,可能是SQL写得烂,可能是表设计不合理,也可能是硬件扛不住了。我见过太多人一上来就调,结果发现瓶颈根本不在这里。今天咱们就从头捋一遍,从最基础的入门技巧到那些只有老司机才懂的实战经验,争取让你看完能直接上手用。

先从最基础的说起——索引。很多人以为加了索引就万事大吉,但索引用不好,反而会拖慢性能。比如,你在一个经常更新的列上建索引,每次插入、删除、更新都要同步维护索引树,写操作的代价直线上升。更常见的问题是索引没被用到。比如你在条件里写了,MySQL就没法用列的索引,因为它在计算表达式。正确的写法是。还有,联合索引的“最左前缀”原则,很多人栽在这里——你建了的联合索引,但查询只用了和,索引就废了。所以建索引之前,先把业务查询捋一遍,看哪些列最常出现在、、里,按频率和选择性排优先级。
再说表设计。我见过一个案例,某电商后台有个订单表,三年下来数据量到了两亿行,每次查询都慢得像蜗牛。后来一看,表里居然有30多个字段,但80%的查询只用到其中5个。这种宽表在OLTP场景下特别坑——每一行数据都很大,导致B+树的叶子节点能存的行数变少,IO次数暴增。解决方案很简单:垂直拆分。把热点字段和冷字段分开,比如订单基本信息一张表,订单详情、备注这些不常查的放另一张表。如果还是扛不住,考虑水平拆分——按用户ID或者时间分表。但分表不是银弹,跨表查询、分页排序都会变得复杂,所以一开始就要规划好分片键。
讲完表结构,很多人会忽略一个关键点——慢查询日志。这是诊断性能问题的第一道防线。我自己的习惯是,在开发环境把设成0.1秒,所有超过100毫秒的查询都记录下来。然后定期用分析,找出频率高、执行时间长的SQL。有一回我发现一个查询明明走了索引,但还是几十万行,仔细一看,原来是和配合出了问题。MySQL在处理加时,如果排序字段没有索引,它会先把所有匹配的行排序,再取前N条,这个排序操作在数据量大时极其昂贵。解决方案是给排序字段加索引,或者用覆盖索引。
再往上走一层,就是参数调优了。很多教程一上来就让你调,但这事儿得看场景。如果你的数据库是写密集型,缓冲池再大也帮不了太多,因为写操作主要卡在磁盘IO上。这时候该调的是和。前者控制重做日志的大小,太小会导致频繁的日志切换和刷盘,太大又会让崩溃恢复变慢。后者是个安全与性能的权衡——设成1最安全,但每次事务提交都要刷盘;设成2或者0性能更好,但万一宕机会丢数据。我一般在非核心业务上设成2,核心业务必须设成1,然后靠SSD来弥补IO瓶颈。
说到IO,硬件层面的优化同样不能跳过。很多人觉得数据库慢就是软件问题,其实硬盘往往是最大的短板。一个简单的测试:用工具测一下磁盘的随机读写IOPS,如果连1000都不到,那再怎么调参数都没用。换个NVMe SSD,IOPS能上万,很多慢查询瞬间变快。另外,内存也很关键——不是越大越好,而是要看你的数据活跃集有多大。如果活跃数据是100GB,你给MySQL分配200GB的缓冲池,剩下的100GB可以用来做操作系统缓存,效果更好。但如果你只有128GB内存,却给缓冲池设了120GB,操作系统没内存做文件缓存,反而会频繁触发swap,性能暴跌。
聊一个很多人踩过的坑——连接数。默认情况下,MySQL的最大连接数只有151。当一个请求进来,需要执行多个查询时,如果并发量上来了,连接池很快就满了。这时候新的请求会排队等待,响应时间急剧上升。更糟糕的是,每个连接都会消耗内存,连接数一多,内存被吃光,MySQL开始OOM。正确的做法是:先压测,确定你的服务器能承受多少并发连接,然后设置比这个值高一点。同时,在应用层用连接池(比如HikariCP)控制并发数,不要让应用无限制地建连接。另外,也要适当调大,避免频繁创建和销毁线程。
说到这儿,你会发现MySQL优化其实是个系统工程——从SQL写法、索引设计、表结构拆分,到参数调优、硬件升级、连接管理,每个环节都可能成为瓶颈。没有一招鲜吃遍天的解决方案,每次优化都要先做监控、抓慢查询、分析执行计划,找到真正的短板再动手。我见过一个团队花了两周调参数,结果问题出在一条没加索引的查询上。所以别迷信技巧,多动手、多分析,才是从入门到精通的唯一路径。


