批量insert性能远超单条:一次多值插入仅触发一次完整执行链路,开销降低90%以上;生产建议每批1000–5000行,配合事务包装可再提效20%–40%;load data infile绕过sql层,速度最快。

因为单条 INSERT 每次都要走完整链路:网络往返 → SQL解析 → 事务开启 → redo log刷盘 → 索引更新 → 提交;而一条 INSERT ... VALUES (...), (...), (...) 只触发一次全流程,开销直接砍掉90%以上。
单条INSERT的隐性开销远超你的直觉
你以为只是“写一行数据”,其实MySQL每执行一次单条 INSERT,都必须:
- 建立或复用连接(若未复用连接池)
- 校验用户权限、表是否存在、列名是否合法
- 生成执行计划(哪怕简单语句也要走解析器)
- 为每条记录单独加行锁、检查唯一索引冲突
- 在默认自动提交模式下,强制刷一次
redo log和binlog - 触发一次缓冲池页加载与可能的B+树分裂
插入1万行?就是1万次上述流程。实测中,纯网络RTT叠加日志刷盘,在跨机房场景下,单条耗时可轻松突破50ms;批量则稳定在200ms以内。
VALUES多值语法的性能临界点在哪
不是越多越好,max_allowed_packet 是硬门槛,但真正卡住你的是内存和锁竞争:
- 默认
max_allowed_packet = 4MB,假设每行平均200字节,理论最多塞约2万行,但生产环境建议控制在1000–5000行/批 - 超过3000行后,
sort_buffer_size或tmp_table_size不足易导致磁盘临时表,性能断崖下跌 - InnoDB对整条语句持锁时间变长,若表上有唯一索引,冲突检查会串行化,反而拖慢并发写入
- 错误定位困难:某一行字段超长或类型不匹配,整条语句失败,报错位置难追溯
事务包装比裸批量INSERT还快20%–40%
即使单条多值 INSERT 自身是原子的,但如果你要插10万行,拆成100条批量语句(每条1000行),再用 BEGIN; ... COMMIT; 包裹,能进一步省掉99次事务启动/清理开销:
- 减少
undo logsegment分配次数 - 合并
binlog写入,降低主从延迟抖动 - 避免因单事务过大触发
innodb_lock_wait_timeout(默认50秒)中断 - 注意:单事务别超50万行,否则可能撑爆回滚段,或让从库复制卡住
LOAD DATA INFILE才是真正的性能天花板
如果数据源是文件(如CSV),LOAD DATA INFILE 比任何SQL批量插入都快10–20倍,因为它完全绕过SQL解析层:
- 不走Parser,不生成执行计划,不校验每行SQL语法
- 直接读取二进制/文本流,按字段分隔符切片后批量写入引擎
- 需确保客户端有
LOCAL INFILE权限,且服务端配置local_infile=ON - 不支持参数化,无法做业务逻辑转换(如字段脱敏、时间戳格式化),适合ETL类原始导入
真正容易被忽略的点是:批量插入快慢,不只取决于语法,更取决于你是否关掉了干扰项——比如应用层没关自动提交、没设 innodb_flush_log_at_trx_commit=2、或者误用了带触发器的表。这些细节一叠加,再好的批量写法也会打五折。











