Skip to content

MySQL 中的索引数量是否越多越好?为什么? ​

  • 标签:后端、MySQL、数据库

🏛 业务架构师 ​

明确回答:索引不是越多越好,索引是"用写性能和存储换读性能"的交易,超出需求就是纯付费。

成本账算清楚:

  • 写放大:每次 insert/update 涉及索引列,所有 B+ 树都要同步维护,页分裂还会产生碎片。交易表 5 个索引和 15 个索引的写入 TPS 可能差一倍,大促下单高峰这就是容量事故的伏笔;
  • 空间成本:每个索引都是一棵完整 B+ 树,索引总量轻松超过数据本身,备份、DDL 变更时间都被拉长;
  • 优化器负担:索引越多,执行计划估算越复杂,选错索引反而引发劣化;
  • 维护成本:没人说得清哪个索引还有查询在用,删没人敢删,成了技术债。

我的治理原则:

  • 数据驱动:只对慢查询日志和调用量统计证明的高频查询建索引,建之前先 EXPLAIN 验证收益;
  • 复用优先:(a,b,c) 已覆盖 (a)、(a,b) 的场景就不重复建;
  • 定期审计:用 sys.schema_unused_indexes 或 pt-digest 找出长期未使用的索引,评估后下线,索引有生命周期;
  • 交易表最克制:下单、支付这类高频写表的索引要做专项评审。

一句话:索引数量是读写比例的函数,由业务画像决定,"多多益善"是把读优化做成了写负担。

🏗 系统架构师 ​

不是,索引是典型的"读优化换写代价 + 空间代价":

  • 写入放大:每加一个索引,insert/update/delete 都要同步维护一棵 B+ 树,页分裂、变更 buffer、redo 都随之增加,5 个索引的表写入开销可能比无索引高一倍以上;
  • 空间占用:每个索引近似一棵独立树,宽表上索引总量轻松超过数据本身,缓冲池被稀释,热数据命中率下降,反而拖慢读;
  • 优化器负担:索引多了优化器估算路径变多,极端情况计划不稳定;
  • 维护成本:大量重复/冗余索引((a) 和 (a,b) 就是冗余),DDL 变更窗口更长。

我的治理标准:单表索引 ≤ 5 个,联合索引优先复用((a,b) 已覆盖单独的 (a));上线前用 sys.schema_redundant_indexes、pt-duplicate-key-checker 清理冗余;低频查询宁可慢一点走缓存或从库,不为偶发查询加索引。索引数量本质是容量规划问题——写多读少的表我会更激进地砍索引。

💻 全栈开发专家 ​

不是,索引是典型的用写性能和空间换读性能。过多的索引有三笔账:

  1. 写放大:每次 insert/update/delete 要同步维护所有涉及的 B+ 树。我压测过一张 6 个二级索引的表,写入 QPS 比去掉冗余索引后低 30%+。
  2. 空间:每个索引是一棵独立的树,联合索引多了磁盘和内存(buffer pool)占用上升,冷数据反而挤掉热数据页。
  3. 优化器选择成本:候选索引多,优化器统计信息稍有偏差就可能选错索引(explain 里明明有更优索引却走了差的),这类问题排查起来非常恶心,最后往往是 force index 收场。

我带团队的实践:

  • 单表索引控制在 5 个左右,联合索引优先,让一棵树服务多个查询。
  • 上线前用 pt-duplicate-key-checker 或 sys.schema_redundant_indexes 清理重复/冗余索引(如已有 (a,b) 再建 (a) 就是白养)。
  • 每次加索引走评审,说明它服务的 SQL 和预期收益,用慢日志回归验证。