批量插入时加索引变慢,因每行插入均触发B+树维护,索引越多写放大越严重;有效优化是先删索引、再批量插入、最后重建索引。

为什么批量插入时加索引反而变慢?
因为 MySQL 在执行 INSERT 时,每插入一行都会触发索引 B+ 树的维护(分裂、合并、回写),索引越多,写放大越严重。尤其当表已有大量数据,且目标字段存在二级索引时,INSERT ... VALUES (...), (...), ... 的吞吐会明显下降。
- 单条插入带 3 个二级索引:约 4 次磁盘随机写(1 行记录 + 3 索引项)
- 批量插入 1000 行:若逐行提交,就是 4000 次随机写;若用事务包住,能减少日志刷盘次数,但索引结构更新仍无法避免
- 真正有效的优化是:**先删索引 → 批量插入 → 再建索引**,前提是业务允许短时间不可用或离线操作
INSERT ON DUPLICATE KEY UPDATE 怎么避免唯一键冲突导致的锁升级?
当使用 INSERT ... ON DUPLICATE KEY UPDATE 更新主键或唯一索引字段时,MySQL 会为每一行匹配的唯一键值加 next-key lock,高并发下极易出现锁等待甚至死锁。这不是语法问题,而是 InnoDB 的悲观锁定机制决定的。
- 确认是否真的需要“存在则更新”:如果只是补漏,可改用
INSERT IGNORE+ 单独的UPDATE语句分两阶段处理 - 确保
ON DUPLICATE KEY UPDATE中的UPDATE子句只修改非索引列,否则可能触发额外的唯一约束检查 - 批量时拆成更小批次(如 500 行/批),降低单次锁持有范围和时间
- 在
WHERE条件中显式指定主键或唯一索引列,避免全表扫描引发的间隙锁扩散
REPLACE INTO 和 INSERT ... ON DUPLICATE KEY UPDATE 的性能差异在哪?
REPLACE INTO 本质是 DELETE + INSERT,会触发两次索引变更(先删旧索引项,再插新索引项),还可能导致自增 ID 跳变、外键级联动作重复执行。而 INSERT ... ON DUPLICATE KEY UPDATE 是原地更新,仅修改聚簇索引记录和受影响的二级索引字段。
网趣购物系统静态版支持网站一键静态生成,采用动态进度条模式生成静态,生成过程更加清晰明确,商品管理上增加淘宝数据包导入功能,与淘宝数据同步更新!采用领先的AJAX+XML相融技术,速度更快更高效!系统进行了大量的实用性更新,如优化核心算法、增加商品图片批量上传、谷歌地图浏览插入等,静态版独特的生成算法技术使静态生成过程可随意掌控,从而可以大大减轻服务器的负担,结合多种强大的SEO优化方式于一体,使
INSERT INTO t (id, name, version) VALUES (1, 'a', 1) ON DUPLICATE KEY UPDATE name = VALUES(name), version = version + 1;
- 如果
version不在任何索引中:只更新聚簇索引页,二级索引完全不动 - 如果
name是二级索引前缀:需更新该二级索引对应项(但不删除重建) -
REPLACE INTO即使只改一个字段,也会让所有二级索引项先被标记删除、再重建,开销翻倍
大批量更新时如何防止索引拖慢 UPDATE 速度?
执行 UPDATE 时,只要 SET 子句中修改了任何被索引的列(包括主键、唯一索引、普通索引),MySQL 就必须同步更新对应索引结构。对百万级以上表,这常常成为瓶颈。
- 优先考虑是否可以绕过索引列更新:比如把状态码存进
tinyint字段并建索引,而不是用varchar(20)存 “processing”、“done” 等字符串再索引 - 临时禁用非必要索引(仅限支持
ALTER TABLE ... DISABLE KEYS的 MyISAM;InnoDB 不支持,需改用DROP INDEX+ADD INDEX) - 用
UPDATE ... JOIN替代子查询,避免因隐式临时表导致索引失效 - 确认 WHERE 条件是否命中索引:没走索引的
UPDATE会全表扫描+逐行加锁,比索引更新本身更耗时









