
批量插入数据时,直接循环执行单条 INSERT 效率极低,关键在于减少网络往返、降低日志开销、避免频繁锁竞争。核心思路是:合并语句、控制事务粒度、合理利用数据库特性。
使用多值 INSERT 语句(最基础有效)
将多行数据拼成一条 INSERT … VALUES (…), (…), (…) 语句,显著减少解析和网络开销。MySQL、PostgreSQL、SQL Server 均支持(注意单语句长度限制,如 MySQL 默认 max_allowed_packet 为 4MB)。
- 一次插入 100–1000 行较稳妥,具体取决于单行数据大小;超过 5000 行易触发超限或锁等待加剧
- 避免在循环中动态拼接大量字符串,建议用参数化方式构建(如 JDBC 的 PreparedStatement.addBatch() + executeBatch())
- PostgreSQL 可配合 ON CONFLICT DO NOTHING 实现带去重的批量写入
分批次提交事务(平衡性能与一致性)
不加事务时每条 INSERT 都自动提交,I/O 和日志刷盘开销巨大;全包一个大事务又可能引发长事务、锁表、回滚段膨胀。应按固定大小分批显式提交。
- 每 1000–5000 条为一批,BEGIN → 批量 INSERT → COMMIT,既减少 commit 次数,又避免事务过长
- 对高并发写入场景,可适当减小批次(如 200–500),缓解行锁/间隙锁争用
- 若中途失败,只需重试当前批次,无需全量回滚
临时禁用约束与索引(仅限导入初期)
大批量导入前,可暂时关闭外键检查、唯一性约束校验,甚至删除非必要索引,导入完成后再重建。适用于初始化、ETL 等离线场景。
- MySQL:SET FOREIGN_KEY_CHECKS=0; ALTER TABLE t DISABLE KEYS; 导入后 ENABLE KEYS
- PostgreSQL:SET CONSTRAINTS ALL DEFERRED; 或临时 DROP INDEX(需评估主键/唯一索引是否必须)
- 注意:此法不可用于线上实时写入,且需确保数据本身满足业务逻辑一致性
选用专用加载工具或扩展语法
绕过 SQL 解析层,走更底层的数据通道,吞吐量提升数倍至数十倍。
- MySQL:用 LOAD DATA INFILE(本地文件需 secure_file_priv 配置允许)或 mysqlimport 工具
- PostgreSQL:用 COPY 命令(支持从 STDIN、文件或程序流读取),比 INSERT 快 5–10 倍
- SQL Server:推荐 BULK INSERT 或 bcp 工具,配合 TABLOCK 提示减少锁开销
- 应用层可结合 JDBC 的 rewriteBatchedStatements=true(MySQL)或 useServerPrepStmts=false 优化批处理










