开放问答
补二级索引后读 P99 降到 35ms,但写 QPS 掉 15%:写入放大成本怎么量化算账
该问题的正文、回答与评论。
提问者 陈砚舟-802 · 状态 open
MySQL慢查询治理二级索引写入放大TCO
【背景】 我负责一套任务调度系统的慢查询治理,主库 MySQL 8.0.32(单主 16C64G,innodb_buffer_pool_size=48G,redo log 默认大小),核心表 t_task 约 6500 万行、当前含 PK + 3 个二级索引共 9.2GB,写入 QPS 日常 1200~1500(INSERT 为主,少量 UPDATE status)。
【现象】
治理前慢查询是 SELECT ... WHERE status='PENDING' ORDER BY priority DESC, created_at ASC LIMIT 50,P99 约 480ms。上周补了联合索引 idx_status_priority_created 后,读 P99 降到 35ms、P999 降到 180ms,肉眼可见收益。但同一张表的写入侧:INSERT QPS 从 1200 掉到 1020 左右(应用侧没改),写入 P99 从 45ms 涨到 58ms,业务侧已经注意到"任务派发变慢"了。
【已尝试的排查】
- SHOW ENGINE INNODB STATUS 的 TRANSACTIONS / SEMAPHORES 段:没有明显的 row lock wait 堆积,log wait 次数正常;
- buffer pool hit rate 仍然 99.9%+;
- 用 performance_schema.events_waits_summary_global_by_event_name 对比加索引前后 30 分钟的 innodb/index_write 与 row_insert 计数,index_write 增量大约和新增索引的写入量对得上,但没有一套公式能把它换算成"每 QPS 写入多花多少 µs";
- 怀疑是新增索引的 B+ 树页分裂 + redo log 双写放大,但没有数据支撑。
【期望得到的答案形态】
- 一个可复现的量化方法:怎么从 InnoDB 层把"多一个二级索引 = 每次 DML 多写多少字节 redo / 多少 page IO / 多少 µs"算出来(最好能给一条 SQL 或一组 psql 采样步骤);
- 一个算账公式或经验阈值:读 P99 收益(480ms→35ms)和写 QPS 损失(-15%)怎么折算成同一把尺子判断"这个索引值不值得留",什么情况下应该考虑删掉旧的 idx_status 或改用 status 分表;
- 如果有团队做过类似"索引增删的 TCO 评估",希望看到你们的做法(工具 / 采样窗口 / 决策记录)。
参考:站内已有 #578 讨论过 DDL 操作本身的锁窗口、#757 讨论过索引命中后 P99 抖动,本篇想问的是索引在线之后持续的写入侧成本,不是 DDL 那一瞬间。
已采纳
回答者
回答正文
评论
暂无评论。