insert时每多一个二级索引就多一次b+树写入,因每行需插入主键索引及各二级索引对应b+树,索引越多随机写、页分裂、锁争用越严重;唯一索引和外键校验无法被change buffer缓存,必须同步执行,成为性能瓶颈。

INSERT 时每多一个索引,就多一次 B+ 树写入
MySQL 的 INSERT 不是只往表里写一行数据就完事。只要该表有 N 个二级索引(非主键索引),InnoDB 就必须把这一行中对应索引列的值,分别插入到 N 棵独立的 B+ 树中。主键索引(聚集索引)写一次,每个二级索引再各写一次——5 个索引 = 至少 6 次磁盘结构更新操作。
这些写入不是简单追加:B+ 树要维持有序,得先查找插入位置、可能触发页分裂、申请新页、加闩锁防并发冲突。索引越多,这类随机写和内存争用就越频繁,耗时自然成倍增长。
唯一索引和外键会额外增加校验开销
如果某个二级索引是 UNIQUE,每次 INSERT 前都得先查一遍该值是否已存在,这个查找本身就要走一次索引树;若涉及外键约束,还要去关联表查记录——这两类检查无法被 Insert Buffer 缓解,属于硬性同步开销。
-
SET unique_checks = 0可临时跳过唯一性校验(导入前确保数据无重复) -
SET foreign_key_checks = 0可禁用外键检查(导入后需手动验证一致性) - 这两项关闭后,
INSERT速度常能提升 2–4 倍,尤其在高基数唯一索引场景下
Insert Buffer 并不能覆盖所有索引类型
InnoDB 的 Insert Buffer(5.6 起升级为 Change Buffer)只对「非唯一、非聚集」的二级索引生效。一旦你建了 UNIQUE INDEX 或 PRIMARY KEY,这部分索引更新就完全绕过缓冲,直接落盘。
这意味着:哪怕你只加了一个 UNIQUE(name),它也会成为整个插入链路上的性能瓶颈点,拖慢所有后续索引的合并节奏。
-
innodb_change_buffering默认值是all,但对唯一索引无效 -
SHOW ENGINE INNODB STATUS中的INSERT BUFFER AND ADAPTIVE HASH INDEX段可查看当前合并状态 - 别指望靠调大
innodb_change_buffer_max_size来加速唯一索引写入
批量插入也救不了过度索引的表
很多人以为改用 INSERT INTO t VALUES (),(),()... 或 LOAD DATA INFILE 就能一劳永逸——其实不然。批量只是减少了 SQL 解析、网络往返和事务开销,但每行数据仍要完整维护所有索引结构。
实测显示:一张有 8 个二级索引的表,插入 10 万行,即使批量提交,耗时仍是 0 索引表的 5 倍以上;而删掉其中 4 个长期 rows_selected = 0 的索引后,耗时直接回落到 2 倍内。
- 用
SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage WHERE object_schema = 'db' AND object_name = 't'查真实使用率 -
information_schema.STATISTICS只告诉你“有没有索引”,不告诉你“用没用上” - 重建索引前先
ALTER TABLE t DISABLE KEYS,比DROP + CREATE快得多,且支持回滚
索引不是装饰品,每一颗都在 INSERT 时实时扣你的 IO 和 CPU。真正难的不是加索引,而是敢在上线前删掉那三个没人用、但写了半年建表语句的 INDEX。











