本节摘要:三个来自生产一线的完整案例——慢查询会诊、批量任务拖垮白天业务、连接池耗尽——完整呈现"定位、处方、验证、复盘"的全过程。案例的价值不在答案,在每一步判断依据了什么证据。
背景。某订单查询接口,业务反馈高峰期从三百毫秒劣化到两秒五,数据库与机器资源都不紧张。
定位。第一步取执行计划与实际执行账单(4.3 的方法):计划显示对订单表做了顺序扫描,估算返回四万行、实际返回四万二——估算本身没问题;顺序扫描四千万行的表,命中占比百分之一,明显不合算。第二步查索引:时间与状态列上有单列索引各一个,但查询条件是两个列的组合过滤,优化器评估后认为单列索引选择度不够,放弃。第三步查统计:表统计信息是三天前的自动收集,期间一批历史数据归档迁移,行数变化百分之五——不是主因,主因是索引结构不匹配。
处方与验证。建组合索引(状态列在前、时间列在后,顺序按选择度与条件写法定),刷新统计信息,基准 SQL 十次中位数从两秒五回到三百一十毫秒,长尾分位同步改善。全程零参数变更。
复盘结论。慢查询的第一嫌疑人永远是执行计划而不是参数;组合索引的列顺序要用条件选择度说话,不靠感觉。
背景。某计费系统凌晨批处理跑八十分钟,但业务方投诉的是"每天上午九到十点交易变慢"。批处理明明在凌晨跑,白天为什么会慢?
定位。按 7.2 的响应路径看三层:业务层上午确实长尾抬升;内核层发现上午的缓冲区命中率从九成九跌到九成三、检查点间隔被压缩;资源层磁盘 IO 在上午出现规律性尖峰。追查时间线,发现批处理的最后一段是"统计刷新加清理",常在八点半到九点收尾——它产生的脏页刷盘与统计收集,恰好压在早高峰的起跑线上。慢的根源不是批处理本身,是批处理的尾巴与早高峰重叠。
处方与验证。三招:批处理最后阶段拆出统计刷新与清理,单独挪到九点半之后错峰;批量段本身再分批,把单批粒度从千万行降到百万行,平缓脏页产生速率;监控加一条"早高峰检查点间隔"观察项。验证:改造后连续五个工作日,上午命中率稳定在九成八以上,交易长尾恢复基线。
复盘结论。批处理的代价不只发生在它运行的时间窗,脏页刷盘与统计收集的"尾巴"会延伸数十分钟;错峰要错的是尾巴,不只是主体。这个案例是 2.2 磁盘账与检查点知识的直接变现。
背景。某营销活动上线十分钟,接口大面积超时,日志显示"获取连接超时"——应用连数据库的连接池被占满。

定位。按传导链逆查:应用线程全在等连接;连接全被占着执行一条活动库存查询;那条查询因活动上线后数据量翻倍、又踩了 4.2 的函数包列陷阱(对时间列套函数导致索引失效),单次执行从五十毫秒劣化到三秒。三层证据链完整:一条慢 SQL、传导到连接占用、放大成全站故障。
处方与验证。三道闸门同时落:应用侧给该语句设语句级超时(快速失败优于占着池子等);连接池配置获取超时与排队上限,防止线程无限堆积;修复索引陷阱并拆分活动表的历史数据。验证:复现压测下连接占用峰值下降七成,故障场景不再复现。
复盘结论。连接池是应用与数据库之间的缓冲带,它的容量按"正常查询耗时乘业务量"设计,一条慢 SQL 就能击穿设计余量;语句超时是性价比最高的保险,建议所有生产连接默认配。
把三个案例的处置路径并排看,结构完全一致:先在业务层定级受损范围;再到内核层用视图与账单定位证据;归因收敛成一句话;处方按"结构性优先于参数性"排序;验证用同口径对照;复盘沉淀一条可复用结论。这套路径没有用到任何高级技巧,全部素材来自第 2 到 4 章的原理与 7.2 的仪表盘——性能优化的门槛不在知识量,在证据链纪律。
优化案例讲多了会给人一种"凡事皆可优化"的错觉,实战里还有第四课:识别不该动手的场景。判据一,业务无感:接口九十五分位五十毫秒,没人投诉,监控无异常——这种"看起来可以更快"的需求,优化收益为负(变更风险大于体验收益)。判据二,数据不足以定位:监控断层、日志被轮转、复现条件不明——先补观测再动手,盲改是事故之源。判据三,收益有时效:业务马上要下线某个模块,为它优化的投入沉底。判据四,根因在别处:应用串行调用三次数据库,数据库单次再快也救不了整体时延——把优化建议还给应用团队,并帮他们把串行改并行,才是真正的解。会拒绝的优化工程师才是可信的优化工程师:你的每次动手都有证据链支撑,你说的"不用动"才有分量。
案例处置完,成果若不固化就会随时间蒸发。固化分三层。知识层:复盘报告进团队知识库,按现象归档——下次同类告警,检索命中率决定响应速度。规则层:案例暴露的监控盲区变成新告警项,案例验证过的参数进入基线表,案例提炼的 SQL 模式进入开发规范。工具层:高频的定位动作脚本化——执行计划采集、等待事件快照、锁链分析各做成一键脚本,把十分钟的排查压到一分钟。三层固化做完,一个案例的价值就从"那一次问题解决了"升级为"这一类问题再也不发生"。衡量一个交付团队的成熟度,看它的固化层有几层就够了。
背景:新版本上线后业务反馈"数据不一致",用户改了资料,刷新页面偶尔还是旧值。定位:数据库侧查证——主库数据已更新,备机同步正常;矛盾指向应用与缓存层。追查发现:开发为"减轻数据库压力"给查询加了五分钟本地缓存,但更新接口改的是数据库,缓存失效逻辑漏写——所谓数据不一致,是缓存里的旧值。处方:更新动作与缓存失效放在同一事务语义下(先更新库、再删缓存、失败重试删),加短过期兜底。验证:压测下不再出现旧值残留。复盘结论有三层:这根本不是数据库故障,但值班若不懂链路就会被牵着在数据库里空转两小时;"加了缓存"这个决定要在架构评审时同步给出失效设计,而不是代码里顺手一行;排障的第一步永远是确认"数据到底存在哪几份"。把这个案例与案例三连读,你会看到同一条链路的两面:连接池是数据库的缓冲带,缓存也是——缓冲带上的问题都会伪装成数据库的问题。
交付的最后一公里是让数据安全搬家——第 8 章讲迁移、生态与演进,为全册收束。