用 insert into ... values (...),(...),... 多值语句+显式事务+关闭自动提交,比存储过程快5–10倍、比逐条插入快百倍;核心在于减少sql解析、网络往返和redo log刷盘次数。

直接上结论:用 INSERT INTO ... VALUES (...), (...), ... 多值语句 + 显式事务 + 关闭自动提交,比存储过程快 5–10 倍,也比逐条插入快百倍。关键不在“怎么写”,而在“怎么发”和“数据库怎么接”。
为什么存储过程插入10万条很慢
MySQL 存储过程是单线程、解释执行的,每轮 WHILE 循环都触发一次 SQL 解析 + 权限校验 + 日志写入,哪怕只插一条记录,开销也不小。更麻烦的是,默认 autocommit=ON,意味着每条 INSERT 都隐式开启并提交一个事务,InnoDB 要刷一次 redo log —— 这才是性能杀手。
常见错误现象:CALL idata() 执行几分钟没反应,或者中途被 ERROR 1205 (40001): Deadlock found 中断(尤其表上有二级索引时)。
实操建议:
- 必须在存储过程开头加
START TRANSACTION,结尾COMMIT - 避免在循环内频繁
COMMIT;若要分段控制,每 5000–10000 行提交一次即可 - 建表时临时去掉非必要索引(如
DROP INDEX a ON t),插完再重建 - 不推荐用存储过程生成百万级以上数据 —— 它不是为这个设计的
真正快的方案:客户端拼多值 INSERT
核心是把 10 万条数据压缩成尽量少的 INSERT 语句发给 MySQL,让服务端一次解析、批量执行。网络往返次数从 10 万次降到几十次,日志写入也大幅合并。
使用场景:你有数据源(比如 Java List、Python list、CSV 文件),能控制插入节奏。
实操建议:
- 单条
INSERT最多塞 1000–2000 行(受max_allowed_packet限制,通常默认 64MB,但实际建议 ≤ 4MB/条) - 每批用一个事务包裹,例如:
BEGIN; INSERT INTO t (id,a,b) VALUES (1,1,1),(2,2,2),...,(1000,1000,1000); COMMIT;
- Java/JDBC 必须加参数
rewriteBatchedStatements=true(否则 MyBatis 或 JdbcTemplate 仍会拆成单条发送) - Python 的
pymysql.executemany()或mysql-connector-python默认就走多值优化,但需确认驱动版本 ≥ 8.0.23
JDBC 连接参数和 MySQL 配置影响极大
很多“明明写了批量却还是慢”的问题,根源在连接串或服务端配置没调对。
容易踩的坑:
- 漏配
useServerPrepStmts=false&cachePrepStmts=true:导致 PreparedStatement 每次重编译 - 忽略
allowMultiQueries=true(某些旧驱动需要它才能执行带分号的多语句) - MySQL 侧
innodb_flush_log_at_trx_commit=2可显著提速(牺牲极小持久性,测试环境可接受) -
bulk_insert_buffer_size建议设为 8M–16M(针对大批次 LOAD DATA 或多值 INSERT)
性能差异示例:同一台机器插 10 万行,autocommit=ON 时耗时 217s;加事务 + 多值 + innodb_flush_log_at_trx_commit=2 后降到 3.2s。
超大规模(>100 万)优先考虑 LOAD DATA INFILE
当数据已存在本地文件(如 CSV),LOAD DATA INFILE 是 MySQL 原生最快的路径,绕过 SQL 解析层,直写引擎。
注意点:
- MySQL 用户需有
FILE权限,且文件必须在数据库服务器本地(或启用local_infile=ON并用LOAD DATA LOCAL INFILE) - 字段分隔符、NULL 处理、日期格式需显式指定,例如:
LOAD DATA INFILE '/tmp/data.csv' INTO TABLE t FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (id,@a,@b) SET a=@a, b=@b;
- 无法触发触发器,也不走 binlog 的 row 格式(除非设置
binlog_format=STATEMENT) - 不适合动态生成数据的场景(比如要插 UUID、当前时间等)
真正难的不是“怎么插”,而是判断哪条路径适配你的数据来源、运维权限和一致性要求——拼 SQL、开事务、调参数、换工具,每一步都得对齐真实约束。











