批量插入数据应优先使用单条INSERT语句带多组VALUES,而非循环执行多条INSERT;MySQL、PostgreSQL、SQL Server均支持,但需注意列数类型匹配及各数据库的值组数量限制;数据源自其他表时宜用INSERT...SELECT。

批量插入数据最直接的方式是用单条 INSERT 语句带多组值,而不是循环执行多条 INSERT —— 这能显著减少网络往返和事务开销。
用 VALUES 列表一次插入多行
MySQL、PostgreSQL、SQL Server 都支持在一条 INSERT INTO ... VALUES 后跟多个括号包裹的值组:
INSERT INTO users (name, email, age)
VALUES
('Alice', 'alice@example.com', 28),
('Bob', 'bob@example.com', 32),
('Charlie', 'charlie@example.com', 25);
注意点:
- 所有值组的列数和类型必须严格匹配
INSERT子句中指定的列 - PostgreSQL 对单条语句的值组数量无硬限制,但 MySQL 默认
max_allowed_packet会限制总长度(常见超限错误:Packet too large) - SQLite 支持但有编译时限制(默认 500 行),可通过
SQLITE_MAX_VARIABLE_NUMBER调整
INSERT ... SELECT 替代大批量导入
当数据来自另一张表、临时表或 CTE 时,INSERT ... SELECT 比拼接大量 VALUES 更安全高效:
INSERT INTO logs_archive (id, message, created_at) SELECT id, message, created_at FROM logs WHERE created_at < '2024-01-01';
适用场景:
- 归档旧数据
- ETL 中清洗后写入目标表
- 避免手动构造千行
VALUES字符串(易出错且难维护)
关键提醒:SELECT 的字段顺序和类型必须与 INSERT 目标列一致;若目标表有自增主键,确保没在 SELECT 中显式提供冲突值(除非有意覆盖)。
不同数据库对批量插入的隐含限制
看似语法一样,但底层行为差异大,容易踩坑:
- MySQL:默认自动提交每条语句;如需真正批量性能,应显式
BEGIN/COMMIT包裹多条INSERT,或调大innodb_buffer_pool_size - PostgreSQL:单条多值
INSERT是原子的,但若其中某行违反约束(如唯一键冲突),整条语句回滚 —— 不像INSERT ... ON CONFLICT可部分处理 - SQL Server:支持
INSERT ... VALUES多行,但超过 1000 行会报错The number of row value expressions in the INSERT statement exceeds the maximum allowed number of 1000 row values;此时必须拆分或改用SELECT ... UNION ALL
实际写批量插入时,别只盯着语法是否合法——先确认目标库的版本、配置上限、事务模型,再决定用 VALUES 列表、INSERT SELECT 还是客户端分批次提交。最常被忽略的是错误恢复:插入中途失败后,如何知道哪些数据已落库、哪些没写入?这往往比“怎么插”更影响线上稳定性。

















