← 返回题目列表

MySQL 二级索引为什么会增加写入成本?如何控制索引数量?

中等 第 20 / 28 题 更新于 2026/07/30
MySQL二级索引写放大索引设计

简化版

二级索引能提升查询,但每次插入、删除、更新相关字段时,MySQL 不只要改数据页,还要维护所有受影响的二级索引页。索引越多,写入成本、磁盘空间、Buffer Pool 压力和页分裂概率越高。控制索引数量的原则是:保留高价值查询索引,合并可复用联合索引,删除长期不用或重复索引,避免为低频查询无限加索引。

详细版

InnoDB 的二级索引叶子节点保存索引列和主键值。写入一行数据时,除了聚簇索引要写,每个二级索引也要插入对应条目。更新索引列时,可能相当于删除旧索引项再插入新索引项。

这就是为什么“索引不是越多越好”。读多写少的表可以适当多建索引,写入频繁的表要更谨慎。优化时不能只看单条 SELECT 变快,还要看整体写入吞吐、锁等待、redo 量和存储成本。

完整版教学

一、二级索引维护成本来自哪里

插入一行要更新聚簇索引。

还要给每个二级索引插入条目。

删除一行要删除多个索引条目。

更新索引列会影响对应索引结构。

索引页可能发生分裂和合并。

二、二级索引结构回顾

InnoDB 表数据按主键组织。

二级索引叶子节点保存二级索引键和主键值。

通过二级索引查到主键后,可能再回表查完整行。

这也是覆盖索引能减少回表的原因。

写入时,这些二级索引都要保持一致。

三、写入成本示例

CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  user_id BIGINT,
  status VARCHAR(16),
  created_at DATETIME,
  KEY idx_user (user_id),
  KEY idx_status (status),
  KEY idx_created (created_at)
);

插入一条订单时,至少要维护主键和三个二级索引。

如果索引更多,写入路径会更重。

四、索引过多的影响

影响表现后果
写入变慢INSERT/UPDATE 成本上升吞吐下降
空间增加索引文件变大存储成本增加
缓存压力Buffer Pool 装更多索引页命中率下降
优化器复杂候选索引变多可能误选
DDL 变慢建索引耗时发布风险增加

五、如何控制索引数量

统计慢查询和真实查询模式。

识别重复索引和左前缀冗余索引。

优先设计可复用的联合索引。

低频后台查询可以接受慢一点,或走离线报表。

写多表要更严格控制索引数量。

每个索引都在向写入链路收费,只是账单常常到高并发时才显现。

六、如何判断索引价值

看查询频率。

看过滤选择性。

看是否能覆盖查询。

看是否能同时满足排序。

看写入成本是否可接受。

长期不用的索引要有清理机制。

七、误区和追问

  • 误区:索引只影响查询,不影响写入。 所有相关写入都要维护索引结构。
  • 误区:查询慢就给每个条件都建单列索引。 多个单列索引不一定等于好的联合索引。
  • 误区:索引越多优化器选择越多越好。 候选过多也可能增加计划不稳定风险。
  • 追问:怎么发现重复索引? 比较索引列顺序、左前缀关系和实际使用情况。
  • 追问:写多读少表怎么设计索引? 只保留核心访问路径,避免为偶发查询加重写入。
  • 追问:删除索引有风险吗? 有,要先确认查询依赖和回滚方案,最好灰度观察。

八、面试收束

回答时先讲二级索引维护机制。

再说明写放大、空间和缓存成本。

最后给出索引治理原则:真实查询驱动、可复用、定期清理。