我见过太多程序员把时间花在优化 SQL 语句上,却忽略了数据库本身的基础配置。前阵子一个朋友跟我抱怨,说他们公司的订单查询慢得要命,每次都要等七八秒。我问他数据库的缓存池设置了多少,他愣了一下说用的是默认值。这就是典型的舍本逐末:你把 SQL 写得再花哨,硬件资源没配置好,数据库就像个没吃饭的壮汉,有力气也使不出来。实际上,数据库性能调优的第一步永远不是改代码,而是检查基础参数。比如 MySQL 的 innodbbufferpoolsize,这个参数决定了数据库能在内存里缓存多少数据,设置得当的话,90% 的查询可以直接从内存读取,根本不用碰磁盘。很多人默认值只有几百兆,服务器明明有 128 GB 内存,却只用了不到 1%,这不是暴殄天物是什么。

索引设计是另一个常被误解的领域。很多开发人员觉得索引越多越好,恨不得给每个字段都加上索引,结果查询没快多少,写入速度反而被拖垮了。我记得有个电商平台,订单表上建了十几个索引,每天几百万笔订单插入时,磁盘 I/O 直接被打满,因为每次插入都要同时更新一堆索引树。实际情况是,索引不是越多越好,而是要精准打击。你需要仔细分析业务查询模式,找出真正高频使用的查询条件,比如根据用户 ID 查订单、根据订单号查详情,这些才是索引的用武之地。那些偶尔用一次的组合查询,完全可以通过定时跑批或搜索引擎来解决。还有个常见错误是把索引建在选择性低的字段上,比如性别、状态这种只有两三个值的字段,索引几乎没用,反而浪费空间。
查询语句的写法确实能带来质的飞跃,但前提是你得理解数据库的执行计划。我见过最极端的例子,有个同事写了一条带子查询的 SQL,看起来挺简洁,结果执行了 30 秒。我让他加上 EXPLAIN 看看,发现子查询被当成了相关子查询,每扫描一行外层数据就执行一次,等于重复执行了几十万次。改成 JOIN 之后,响应时间直接降到 0.1 秒。这种问题在日常开发中很常见,很多人写 SQL 时只关注语法对不对,根本不看执行计划。其实数据库查询优化器的能力远比想象的要强,但前提是要给它正确的引导。比如避免在 WHERE 子句中对字段做函数运算,像 这种写法会让索引失效,改成范围查询就能利用索引。这些小细节,改一个就能省下几秒甚至几十秒。
硬件层面的话题容易被忽视,但它往往是性能瓶颈的终极推手。数据库本质上是个 I/O 密集型的应用,磁盘速度决定了数据读取的天花板。我有个客户,数据库服务器用的是机械硬盘,每天中午高峰期查询响应时间都在 5 秒以上。后来换成 NVMe 固态硬盘,同样的代码、同样的数据量,响应时间直接降到 0.5 秒以下。这还不算完,内存大小、CPU 核心数、网络带宽每一样都可能成为瓶颈。特别是现在很多公司用云数据库,觉得弹出来就能用,完全不管底层配置。实际上,云数据库的实例规格选择很讲究,IOPS 和吞吐量都有上限,选了低配实例,业务量一上去立马就崩。所以性能调优一定要从硬件排查起,别一上来就改代码,那是本末倒置。
分区表和分库分表是两个不同的概念,很多人混为一谈。分区表是在同一台服务器上,把一张大表按某个字段划分为多个物理分区,查询时只扫描相关分区,数据量大时效果特别明显。比如日志表按月份分区,查上个月的数据时只扫一个分区,速度能快几十倍。而分库分表是把数据分散到多台服务器上,解决的是单机性能上限的问题。这两种方案都不适合小规模场景,如果你的表只有几百万行数据,分区反而会增加管理复杂度。但当你面对上亿行数据时,不分表就是自寻死路。我见过一家公司,订单表到了 5 亿行,没做任何分区,每次按用户 ID 查历史订单都要扫全表,硬生生把数据库搞垮了。后来按用户 ID 哈希分成 64 张表,查询速度提升了一百倍以上。
缓存是数据库调优的终极武器,但用不好就是双刃剑。很多团队一上来就加 Redis,把热点数据全塞进去,结果缓存和数据库的数据不一致,业务逻辑乱成一锅粥。我建议先分析业务特性,区分哪些数据适合缓存。比如用户基本信息这种很少变动的数据,缓存命中率极高,可以放心缓存。但像库存数量这种实时要求高的数据,缓存反而会引入脏数据问题。还有一个关键点是缓存策略要跟业务节奏匹配,比如电商大促期间,热点商品访问量暴增,缓存一旦失效,直接冲到数据库上,瞬间就能把数据库打垮。所以缓存预热、过期时间、降级方案都得提前设计好,不能等到出事再补救。
数据备份和恢复策略看似与性能无关,但实际上影响深远。很多公司的备份都是在业务高峰期做的,导致数据库 I/O 被占满,查询响应时间飙升。更糟的是,有些备份工具全量备份时会对表加锁,直接阻塞写入操作。我建议把备份时间安排在凌晨低峰期,并使用流式备份,减少对在线业务的影响。同时,恢复速度也要纳入考量,如果数据库崩溃后恢复需要 8 小时,那这 8 小时就是业务中断的时间。所以性能调优不只是让查询变快,还要确保在极端情况下能快速恢复。慢查询日志一定要开启,这是排查性能问题的第一手资料。很多团队等到出事了才临时打开日志,等收集到数据时问题已经造成损失。


