【背景】 做了 5 年 DBA,日常被业务方问得最多的一句话是:「这条查询 P99 高,能不能加个索引把它打下来?」我的默认反应是先看 EXPLAIN 和写入路径,再决定动不动索引。但最近半年复盘慢查询工单时我发现,团队里两种做法各占一半,而且谁也说服不了谁,所以想借这里把分歧摊开聊聊。
【常见分歧 / 几种做法】
- 「覆盖索引派」:只要 SELECT 的列都能被索引覆盖,就不回表,P99 立降一个量级。做法是加一个包含高频列的组合索引,成本看起来只是"多一个索引"。
- 「改查询派」:先砍列、改 JOIN、推下推到存储层,索引不动。理由是索引会放大写入:每条 INSERT/UPDATE 都要维护所有二级索引,列一多 B+ 树就宽,缓冲池命中率反而可能掉。
- 「都先别动派」:先确认这条查询是否真的在关键路径上、QPS 多高、P99 目标是多少——很多工单最后发现是调用方在循环里单条查,改成分批 IN 查询后索引根本不用加。
我自己的几个观察(供拍砖):
- 覆盖索引在「读多写少 + 列稳定」的报表/查询场景收益很实在,我们有个订单状态查询,加覆盖索引后 P99 从 48ms 降到 9ms,写入侧 TPS 不高(几百),基本无感。
- 但在「写密集 + 索引已经 6~7 个」的核心交易表上,再塞一个 4~5 列的覆盖索引,缓冲池 miss 率确实涨过(我们从 0.3% 涨到 1.1%),写入 P99 抖了 30%+,这个代价当时没人提前算。
- 真正让我难受的是决策标准:目前团队是「谁提出工单谁拍板」,没有一套统一的「加索引 vs 改查询」的成本核算模板。
【我的倾向与理由】 我倾向先走一条两步决策:
- 先算写入放大:看该表当前二级索引数量、平均行大小、TPS,估算新增一个 k 列索引对写入路径的额外开销(可以用 sysbench 或线上压测对比 INSERT 延迟)。
- 再算读取收益:看这条查询的 QPS × 当前 P99 超目标幅度,折算成「用户感知收益」或「SLO 预算」。 写入放大可控 + 读取收益显著 → 加覆盖索引;写入放大不可控 → 优先改查询或走读副本。 核心理由:索引不是免费的,它是用写路径的持续成本换读路径的一次性收益,这笔账必须显式算,而不是凭「能快就加」。
【想听大家在什么场景下怎么选】
- 写密集表(TPS 5k+)上,你们敢加覆盖索引吗?踩过什么坑?
- 有没有一套可复现的「加索引成本评估」流程或工具(比如基于 performance_schema 或 sysbench 的对比模板)?
- 「改查询优先」派:你们怎么说服业务方接受改 SQL 而不是加索引?改 SQL 的回归测试成本怎么控?
- 有没有团队把「索引数量上限」写进 code review 规范?设几个合适?
欢迎拿你们线上的真实数据来聊,尤其是写入侧的量化代价——这块我目前最缺参照。
0赞
0收藏
0楼层