我做了十几年数据库运维,见过太多团队被慢查询折磨得死去活来。每次线上告警响起来,第一反应就是看数据库,十有八九是索引没建好或者SQL写得太随意。今天不聊那些虚头巴脑的理论,直接说几个我实际用下来最管用的优化手段,每一条都是踩过坑总结出来的。

先说说索引这件事。很多人以为索引就是加个字段就完事,实际上联合索引的字段顺序能决定生死。我见过一个订单表,查询条件是状态加创建时间,有人建了(status, createdat)的联合索引,结果执行计划还是走了全表扫描。为什么?因为状态字段的区分度太低,就那么几个枚举值,索引选择性差到跟没有一样。正确做法是把高区分度的字段放前面,比如把createdat放首位,再配合status过滤,性能直接提升几十倍。还有最左前缀原则,这个必须刻在脑子里,建索引的时候多想想你的查询到底用到了哪些字段,别整些花里胡哨的没用的组合。
索引不能乱建,但也不能不建。有些开发同学为了省事,什么字段都往索引里塞,结果写入性能惨不忍睹。每次插入都要更新所有索引,数据量一大,磁盘IO直接拉满。我见过最夸张的一个表,二十几个字段建了十六个索引,写入延迟从几十毫秒飙到两秒多。索引不是越多越好,得看实际查询模式。把慢查询日志捞出来,看看哪些查询最频繁,针对性地建索引,这才是正道。那些建了从来没被用到的索引,趁早删掉,留着只会拖累写入。
说完索引,得聊聊SQL本身。很多性能问题,根子不在数据库,在写SQL的人。我经常看到有人写SELECT *,把几百个字段全捞出来,然后代码里只用两三个。这不仅浪费网络带宽,还会让数据库做大量无谓的硬盘扫描。正确姿势是只查出你要用的字段,能用覆盖索引就尽量用覆盖索引。还有子查询和JOIN,这俩用不好就是性能杀手。我记得有个统计报表,用了三层嵌套子查询,跑一次要四十秒,后来改写成两个JOIN加一个临时表,时间缩到两秒以内。不是说子查询不能用,而是得看执行计划,有时候数据库优化器会把子查询改写成JOIN,有时候又不会,自己心里得有数。
说到执行计划,这玩意儿是每个DBA的必修课。EXPLAIN一下,看看是不是走了全表扫描,有没有用到索引,扫描了多少行,排序和临时表的情况怎么样。我之前处理过一个线上事故,一个分页查询越翻越慢,翻到后面几页直接超时。EXPLAIN一看,原来是LIMIT偏移量太大,数据库得把前面所有行都扫一遍才能跳到目标位置。解决方案也简单,改成基于游标的分页,或者用上次查询的一条记录ID作为起点,性能问题瞬间消失。这种问题不跑执行计划,光靠猜,猜一辈子也猜不出来。
还有个大杀器叫分区表。很多人一听分区就觉得是高大上的东西,其实就是把一个大表按某个维度拆成多个物理存储单元。我有个用户行为日志表,一天新增几千万条数据,查询的时候经常要按时间范围过滤。后来按月份做了RANGE分区,查询指定月份的数据时,数据库只用扫描对应分区,其他分区碰都不碰,查询时间从几十秒降到几百毫秒。但分区也不是银弹,得结合业务场景来设计分区键。你要是按性别分区,两三个分区顶天了,一点用没有。分区键得选查询过滤条件里最常用的那个字段,而且数据分布要均匀,不然有的分区数据爆炸,有的分区空空如也,反而拖慢性能。
缓存这块,很多团队容易走极端。要么什么都不缓存,所有请求都打到数据库上,扛不住就加机器;要么什么都往Redis里塞,缓存穿透、击穿、雪崩接踵而至。我的经验是,先搞清楚数据访问的热点分布,把那些读多写少、实时性要求不高的数据放到缓存里。比如商品详情、用户基本信息这类数据,缓存个几分钟完全没问题。但库存、余额这种强一致性的数据,千万别碰缓存,否则出了问题,程序员背锅都背不过来。缓存更新策略也很重要,我之前见过一个团队用了先删缓存再更新数据库的方案,结果并发请求一来,缓存被删了,数据库还没更新完,其他线程又把旧数据写回缓存,数据不一致的问题持续了好几个小时。
说说连接池和数据库参数调优。连接池不是越大越好,有时候连接数上去了,数据库反而更慢,因为线程切换和锁竞争消耗了大量CPU。我见过一个项目,最大连接数设置成500,结果数据库CPU使用率直接飙到99%,应用响应时间反而更长了。后来把连接数降到100,配合连接池的等待队列机制,整体吞吐量反而上去了。数据库参数也是,innodbbufferpoolsize这个参数很关键,一般建议设置为物理内存的70%左右,太小了频繁刷盘,太大了又会跟操作系统争内存。还有maxconnections、innodbflushlogattrx_commit这些参数,得根据业务类型来调,不是抄个模板就完事的。
数据库优化这件事,说到底还是得回到业务本身。技术手段再多,也得搞清楚你的数据长什么样、查询模式是什么、瓶颈在哪里。我见过太多团队,一上来就堆机器、加缓存、调参数,结果问题压根不在这。与其瞎折腾,不如先把慢查询日志和监控数据捞出来,好好分析一下,找到真正的痛点再动手。工具和方法都是死的,关键是用的人能不能灵活运用。你把这些方法吃透了,遇到问题心里就有底,知道该从哪里下手,不至于每次都被线上告警追着跑。


