← 返回题目列表

MySQL 批量插入和批量更新如何优化?

高频 中等 第 7 / 28 题 更新于 2026/07/29
MySQL批量写入INSERTUPDATE

简化版

批量写入要减少网络往返和事务提交次数,控制批大小,利用批量 INSERT、事务、预编译和合理索引;同时避免单次事务过大导致锁等待、redo/binlog 暴涨和主从延迟。

详细版

逐条写入最常见的问题是每行一次网络请求、一次 SQL 解析、一次事务提交,吞吐很低。批量插入可以用一条 INSERT ... VALUES (...), (...), ...,或在一个事务中执行多条预编译语句。

批量更新要更谨慎。按主键分批、按稳定顺序处理,可以减少锁冲突;每批 500 或 1000 行之类的大小需要根据表结构、索引、机器和业务压力压测确定。

优化不是把所有数据塞进一个巨大事务。过大事务会占用 undo、redo、binlog,锁持有时间变长,失败回滚成本也高。正确做法是分批、限速、监控和可恢复。

完整版教学

一、逐条写为什么慢

逐条写入会放大固定成本。

INSERT INTO logs(user_id, content) VALUES (1, 'a');
INSERT INTO logs(user_id, content) VALUES (2, 'b');
INSERT INTO logs(user_id, content) VALUES (3, 'c');

每条语句都可能经历网络发送、解析优化、执行、提交、写日志。如果有 10 万行,就有 10 万次类似固定开销。

记忆钩子:批量写入优化的第一原则,是减少“每行一次”的固定成本。

二、批量 INSERT 怎么写

常见批量插入:

INSERT INTO logs(user_id, content)
VALUES
  (1, 'a'),
  (2, 'b'),
  (3, 'c');

它减少 SQL 往返和解析开销,也能让 InnoDB 更集中地写日志。

如果一次插入 10 万行,不建议拼成一条超大 SQL。可以按批处理:

每批 500~2000 行
批间短暂停顿或按负载限速
失败后记录批次位置,支持重试

具体批大小没有万能值,需要压测。字段多、索引多、行大时,批大小应更保守。

三、事务提交次数很关键

如果每条写入都自动提交,事务提交成本会非常高。

START TRANSACTION;
INSERT INTO logs(user_id, content) VALUES (1, 'a');
INSERT INTO logs(user_id, content) VALUES (2, 'b');
INSERT INTO logs(user_id, content) VALUES (3, 'c');
COMMIT;

把多条写入放进一个事务,可以减少提交刷日志的次数。但事务过大也有风险。

事务大小优点风险
每行提交简单吞吐低
中等批次吞吐和风险平衡需要批次控制
超大事务提交次数少锁久、回滚慢、日志压力大

面试回答要强调“适度批量”,不是“越大越好”。

四、批量更新要按索引和顺序处理

批量更新如果没有命中索引,会扫描和锁住大量行。

UPDATE orders
SET status = 'expired'
WHERE expire_time < NOW()
  AND status = 'unpaid'
LIMIT 1000;

适合的索引可能是:

CREATE INDEX idx_status_expire ON orders(status, expire_time);

为了减少死锁和锁冲突,批量更新最好按主键或索引顺序推进:

id 1~1000
id 1001~2000
id 2001~3000

不要多个任务用不同顺序更新同一批数据。

五、索引数量会影响写入

每插入或更新一行,MySQL 不只改数据页,还要维护相关二级索引。

假设一张表有 1 个主键、8 个二级索引,插入 100 万行时,要维护 8 棵二级索引 B+ 树。索引越多,写入越慢。

批量导入前可以评估:

是否有冗余索引
是否能先导入再建索引
是否影响线上查询
是否需要关闭非必要触发器或外部同步

线上业务表不能随便删索引或延迟建索引,但离线导入、初始化表时可以利用这个思路。

六、复制延迟和日志压力不能忽略

批量写入会产生大量 redo log 和 binlog。从库要重放这些变更,如果主库短时间写入太快,从库可能明显延迟。

执行批量任务时应监控:

主库 QPS / TPS
redo 写入压力
binlog 大小
从库延迟
锁等待
慢查询和业务错误率

如果发现延迟上升,可以降低批大小、增加批间 sleep、切分时间窗口,或改到低峰执行。

七、常见误区与追问

  • 误区:批越大性能越好。 超大批次会带来锁、日志、回滚和复制延迟风险。
  • 误区:批量更新不需要索引。 没有索引会扫描和锁住大量行,影响线上业务。
  • 误区:只要用了事务就一定快。 事务要控制大小,过大事务可能更危险。
  • 误区:写入优化只看主库。 主从复制延迟和下游消费也要监控。
  • 追问:批量插入推荐多大一批? 没有固定值,常从几百到几千行压测,按行大小、索引数和负载调整。
  • 追问:如何降低死锁概率? 按相同索引顺序分批更新,缩短事务,减少单批锁范围。

八、加强记忆

批量写入优化抓住“批量、事务、索引、限速、监控”。减少固定成本能提吞吐,但不要变成超大事务;线上批处理要可暂停、可重试、可观察,别让一次任务把主从和业务一起压住。