唯一索引写入时强制触发磁盘随机读,因需校验唯一性而绕过change buffer;普通索引可缓存更新至change buffer,减少随机i/o,提升写性能。

唯一索引写入时强制触发磁盘随机读
当目标索引页不在 buffer_pool 中时,唯一索引必须先把对应页从磁盘读入内存,才能校验是否违反唯一性。这个“先读再判”的过程绕过了 change_buffer,每次写都多一次随机 I/O。常见现象是:innodb_buffer_pool_reads 突增、写吞吐骤降、慢日志里频繁出现 INSERT ... ON DUPLICATE KEY UPDATE 耗时高。
普通索引能用 change_buffer 缓存更新
普通索引不校验唯一性,InnoDB 允许把 INSERT/UPDATE/DELETE 对二级索引的变更暂存在 change_buffer 中,等该页后续被读入内存或后台线程 merge 时再批量应用。这省掉了大量随机磁盘读。实操要点:
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
-
innodb_change_buffering默认为all,无需改;但若只关心插入性能,可设为inserts -
innodb_change_buffer_max_size默认 25,可动态调至 50(SET GLOBAL innodb_change_buffer_max_size = 50),但别设 100 —— 会挤占buffer_pool查询缓存空间 - 机械硬盘(HDD)场景下收益最明显;SSD 上虽延迟低,但高并发离散写仍能感知差异
NULL 值会让唯一索引的“唯一性”失效
MySQL 中 UNIQUE 索引允许任意多个 NULL,因为 NULL != NULL。比如给 email 加了 UNIQUE 却没加 NOT NULL,结果插入 10 条 email IS NULL 全成功——业务以为字段必填且唯一,实际已失控。检查方式:SHOW CREATE TABLE t; 看约束是否含 UNIQUE NOT NULL。
应用层已做幂等,数据库层还加 UNIQUE 是双输
如果 Java 服务已用分布式锁 + 幂等表 + 事务校验确保 id_card 不重复,那数据库再加 UNIQUE INDEX uk_id_card (id_card) 就纯属冗余:既拖慢写入(失去 change_buffer),又增加死锁概率(多个事务争抢同一索引页做唯一校验),还让错误提示更难定位(Duplicate entry 'xxx' for key 'uk_id_card' 容易被误判为数据污染)。真正需要 UNIQUE 的只有两种刚性场景:外键引用列 或 多系统直连 DB 且无法统一幂等。










