SQL批量插入性能优化核心是减少通信与事务开销,推荐多值INSERT、显式事务分批提交、临时禁用约束索引,并优先使用原生批量接口如MySQL的rewriteBatchedStatements或PostgreSQL的COPY。

SQL批量插入性能优化的核心在于减少通信开销、降低事务和日志压力、避免单行逐条执行。关键不是“一次插多少”,而是“怎么插更省资源”。
合并多行VALUES,用一条INSERT代替多次
单条 INSERT … VALUES (a),(b),(c) 比三条 INSERT … VALUES (a) 分别执行快数倍——省去了重复解析、权限检查、网络往返和事务开销。
- MySQL/PostgreSQL/SQL Server 都支持多值语法:INSERT INTO t(col1,col2) VALUES (1,'x'),(2,'y'),(3,'z');
- 建议每批 1000–5000 行(具体视单行数据大小调整),避免单条语句超长触发协议限制或内存溢出
- 不要拼接上万行进一个VALUES,容易触发 max_allowed_packet(MySQL)或参数绑定上限(JDBC)
关闭自动提交,显式控制事务边界
默认每条 INSERT 都是独立事务,频繁刷盘日志(WAL/redo log)是最大瓶颈之一。将多条插入包裹在 BEGIN / COMMIT 中可大幅降低IO压力。
- 示例(MySQL):START TRANSACTION; INSERT ... ; INSERT ... ; COMMIT;
- PostgreSQL 推荐使用 BEGIN; ... ; COMMIT;,避免隐式事务
- 注意:事务过大(如百万级插入)可能撑爆undo表空间或锁表太久,需分批次提交(如每 1w 行 commit 一次)
临时禁用非必要约束与索引(仅限导入初期)
外键检查、唯一性校验、触发器、二级索引维护都会在每行插入时实时计算,批量写入前临时停用可提速 2–10 倍(取决于索引数量和数据分布)。
- MySQL:禁用外键检查 SET FOREIGN_KEY_CHECKS = 0;;删除/重建索引比在线维护更快
- PostgreSQL:SET CONSTRAINTS ALL DEFERRED; 或建表时用 NOT VALID 约束,导入后再 VALIDATE CONSTRAINT
- SQL Server:禁用索引 ALTER INDEX IX_Name ON T DISABLE;,导入后 REBUILD
- 务必在导入完成后恢复并验证一致性,否则后续查询可能出错
用原生批量接口替代ORM逐条save
JPA/Hibernate 的 saveAll() 默认仍是循环执行单条 INSERT;MyBatis 的 <foreach> 可生成多值语句,但需手动配置 batch=true 和 rewriteBatchedStatements=true(MySQL JDBC)。
- Java JDBC 推荐:启用 rewriteBatchedStatements=true(MySQL)或 useServerPrepStmts=false(兼容旧驱动)
- PostgreSQL 推荐使用 copy 协议(COPY t FROM STDIN),比 INSERT 快 5–20 倍,适合千万级初始加载
- 避免在循环里 new PreparedStatement,应复用同一 Statement 实例 + addBatch() + executeBatch()











