【背景】
做了 10 年 DBA,慢查询治理是日常里的日常。但每次拉出一个月的 slow_log 做治理规划时,团队内部经常吵起来——不是技术分歧,而是优先级分歧。
我最近在一个 200 张表、单实例 64C256G 的 MySQL 8.0 实例上做了盘点,拉出两类典型:
- A 类(低频长耗时):3 条查询,单条 P99 在 8~15s,但每天只触发 20~50 次(报表聚合、跨表 JOIN 5+ 张宽表)。单条慢,但累计 CPU 占比不到 2%。
- B 类(高频短耗时):12 条查询,单条 P99 在 30~80ms,但 QPS 合计 12000+,累计 CPU 占比 34%。单条不慢,但把索引页的 buffer pool 命中率从 99.7% 打到 97.2%。
两类都该治,但人只有 3 个、窗口只有 2 周,先动哪个?
【常见分歧 / 几种做法】
我见过三种流派:
流派一:先治 TOP N 长耗时("大虫子"策略) 理由:单条 15s 的查询在高峰期会锁住连接池、拖垮 P99,一次事故的回滚成本远大于 3 条查询的优化成本。"先止血再治本"。 我见过一个团队按这个原则,花 2 天把 3 条 JOIN 改成了预聚合 + 物化视图,P99 从 2.3s 降到 180ms,当晚发版,零事故。
流派二:先治高频短查询("蚂蚁搬家"策略) 理由:12000 QPS × 50ms 的累计资源消耗,才是 buffer pool 命中率下降、连接池排队、GC 压力上来的真正根因。不治高频,A 类长查询的 P99 只会更差(因为 buffer pool 被高频查询的随机 I/O 挤占了)。 我见过一个团队按这个原则,把 12 条查询中 5 条的索引从二级索引改成了覆盖索引(消除回表),CPU 从 62% 降到 38%,P99 从 2.3s 降到 400ms——一条长查询都没动。
流派三:按业务影响面排序("谁疼治谁"策略) 理由:技术指标是代理指标,真正该排序的是"这条查询挂了,影响多少用户 / 多少下游 / 多少营收"。一条 15s 的报表查询如果只影响内部分析师,优先级低于一条 50ms 但影响 200 万用户下单链路的查询。 我认同这个方向,但实操中"影响面"很难量化——谁来定义?PM?DBA?还是值班 SRE?定义权一换,优先级就变。
【我的倾向与理由】
我倾向于流派二 + 流派三的混合,但有一个硬前提:
先花半天把 buffer pool 命中率、InnoDB rows_read/s、连接池 pending 线程数这三个指标的 7 天基线拉出来,再决定优先级。
为什么?因为慢查询的"慢"不是孤立的。我见过太多案例:单条查询 80ms 看着不慢,但 12000 QPS 的累计 I/O 把 buffer pool 命中率打到 95% 以下,然后所有查询(包括那些"只跑 20 次"的长查询)的 P99 全部恶化 3~5 倍。这时候你治 A 类长查询的 SQL,收益只有 20%;你治 B 类高频查询的索引,收益是全局 60%+。
但有一个例外:如果 A 类长查询涉及大事务 / 大 DML / 锁等待链,那它的优先级无条件高于 B 类——因为长事务的锁等待会级联,一条 15s 的 UPDATE 可以把后面 200 条 50ms 的 SELECT 全部拖成 15s。这种时候"大虫子"必须优先。
【想听大家怎么选】
几个具体问题想抛出来:
- 你的团队有没有慢查询治理的 SOP? 还是每次全靠 DBA 个人经验拍?如果有 SOP,排序依据是什么(耗时?QPS?业务影响?锁等待深度?)
- buffer pool 命中率从 99.7% 掉到 97% 这个区间,你们有没有告警? 我见过太多团队只告警 < 90%,但 97%~90% 这个"温水煮青蛙"区间才是 P99 开始劣化的起点。
- 高频短查询的索引优化(覆盖索引消除回表),你们愿意为此增加索引维护成本吗? 我见过一个表加了 7 个索引后,写入 P99 从 8ms 涨到 22ms——读快了写慢了,这笔账你们怎么算?
- 有没有人用"慢查询影响面评分"做过量化排序? 比如:影响用户数 × 单条耗时 × 触发频率 / 修复成本,算出一个 ROI 分数?如果有,公式长什么样?
不是要标准答案,是想看看大家在不同规模(单实例 16C vs 分库分表 64 实例)、不同业务形态(OLTP 为主 vs 混合 OLAP)下,到底怎么选、为什么这么选。