索引越多,INSERT/UPDATE/DELETE越慢,因每次写入需同步更新聚簇索引和所有二级索引,触发多次B+树操作;唯一索引因强制重复校验无法使用change_buffer,写入开销更大;批量导入时应临时删索引、调大缓冲参数;冗余索引是写入瓶颈主因,应优先清理而非加缓存。
索引越多,INSERT/UPDATE/DELETE 越慢
MySQL 每次写入数据时,不仅要修改聚簇索引(主键 B+ 树),还要同步更新所有相关二级索引。每个二级索引都是一棵独立的 B+ 树,插入一条记录可能触发多次磁盘页分裂、节点调整和缓冲池刷脏。实测表明,一张表从 0 个索引增加到 5 个二级索引,
吞吐量可能下降 40%~70%,尤其在
不足、磁盘 I/O 瓶颈明显时更甚。
常见错误现象:
中大量写操作卡在
或
状态;
显示
增长缓慢但
激增。
单条
语句涉及 N 个索引 → 至少 N+1 次 B+ 树写入(含聚簇索引)
修改了索引列 → 原索引项删除 + 新索引项插入,开销翻倍
同样需从所有索引中定位并移除对应条目,非主键删除更耗时
唯一索引和普通索引的写入代价差异很大
唯一索引(
)在写入前必须做重复值校验,而普通索引不需要。这个校验过程会强制走一次索引查找(即使使用
,也要先查唯一约束),导致事务持有行锁或间隙锁时间更长,容易引发锁等待甚至死锁。
使用场景:用户注册表的
字段加
,高并发写入时
可能因唯一检查阻塞其他线程。
普通索引可被
缓存(
默认开启),延迟合并到磁盘
唯一索引无法使用
做插入缓存,必须实时查找校验
和
同样触发唯一性检查,不比
更轻量
批量写入时索引维护策略要主动干预
默认情况下,MySQL 对每条
都立即更新索引。但在大批量导入(如 ETL、日志归档)场景下,可以临时关闭非必要索引或调大缓冲参数来提速。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
实操建议:
导入前用
删除非关键二级索引,导入完成再重建(注意重建过程仍锁表)
设置
(256MB)提升
效率
对
,确保
≥ 数据总大小的 50%,否则频繁刷脏拖慢索引构建
避免在
下循环执行单条
,改用批量
读写失衡时优先砍冗余索引,而非盲目加缓存
很多团队遇到写入变慢第一反应是加 Redis 或调大
,但真正瓶颈常在索引设计本身。通过
或
(MySQL 8.0+)可快速识别长期未被
使用却持续拖累写入的索引。
容易被忽略的点:
复合索引中前导列未被查询条件使用 → 整个索引对读无效,但写入照常维护
/
列上的全文索引(
)写入开销远高于普通 B+ 索引,且无法用
低基数列(如
只有 0/1)建索引几乎不影响读性能,却白耗写资源
索引不是越多越好,而是越精准越省事。一个没被
用上的索引,就是纯写入税。
INSERTinnodb_buffer_pool_sizeSHOW PROCESSLISTupdatinginsertINFORMATION_SCHEMA.INNODB_METRICSdml_insertsindex_page_splitsINSERTUPDATEDELETEUNIQUE KEYchange bufferemailUNIQUEINSERT ... ON DUPLICATE KEY UPDATEchange_bufferinnodb_change_buffering = insertschange_bufferINSERT IGNOREREPLACE INTOON DUPLICATE KEY UPDATEINSERTALTER TABLE t DROP INDEX idx_xxxSET SESSION sort_buffer_size = 268435456CREATE INDEXLOAD DATA INFILEinnodb_buffer_pool_sizeautocommit=1INSERTINSERT INTO t VALUES (...), (...), (...)query_cache_sizept-duplicate-key-checkersys.schema_unused_indexesSELECTTEXTJSONFULLTEXTchange_bufferstatus TINYINTEXPLAIN