mysql存储过程不支持bulk insert,仅可用多值insert或load data infile;游标因单行处理性能极差,应避免用于百万级插入;推荐关事务+批量拼接+分段循环,每批2000行并禁用唯一检查以提升效率。

MySQL 存储过程中没法用 BULK INSERT —— 那是 SQL Server 的语法,直接写会报错 ERROR 1064;游标在百万级插入里基本等于自废武功,性能极差,别用。
MySQL 存储过程里根本不存在 BULK INSERT
SQL Server 的 BULK INSERT 是原生命令,MySQL 没有对应实现。你在 MySQL 里写 BULK INSERT ... FROM ...,只会收到类似这样的错误:
ERROR 1064 (42000): You have an error in your SQL syntax near 'BULK INSERT ...'
MySQL 原生支持的高效批量导入方式只有两个:LOAD DATA INFILE(最快)和 INSERT ... VALUES (...), (...), ...(多值插入)。存储过程里能用的,只有后者 —— 但必须规避逐行 INSERT 的陷阱。
为什么游标在百万插入中完全不适用
MySQL 游标本质是单行提取 + 单行执行,配合 INSERT 就是「查一行、插一行、刷一次日志、更新一次索引」,I/O 和锁开销爆炸。实测过:用游标插 10 万条,比关事务的 while 循环还慢 3–5 倍。
- 游标隐式开启结果集扫描,内存占用高,容易触发
max_heap_table_size或sort_buffer_size限制 - 每次 fetch 都要走一次引擎层,InnoDB 行锁+间隙锁频繁争抢
- 无法利用 MySQL 的 statement batch 优化机制(如 multi-value insert 的 parse/plan 复用)
真正可行的存储过程方案:关事务 + 批量拼接 + 分段循环
核心思路是:不用游标,不用预处理单条语句,用字符串拼接生成大批次 INSERT,每批 1000–5000 行,再统一执行。关键控制点:
- 必须显式
START TRANSACTION,结尾COMMIT,避免自动提交放大开销 - 每批数据量控制在 2000 行左右:太小(如 100)仍频繁提交;太大(如 10000)易触发
max_allowed_packet截断 - 用
CONCAT拼接 values,避免PREPARE/EXECUTE的解析开销(那玩意儿在循环里反而更慢) - 插入前临时禁用唯一检查:
SET UNIQUE_CHECKS=0,结束后恢复
示例节选(插入 user 表,每批 2000 条):
DELIMITER $$ CREATE PROCEDURE insert_user_batch(IN total INT) BEGIN DECLARE i INT DEFAULT 0; DECLARE batch_size INT DEFAULT 2000; DECLARE sql_part TEXT DEFAULT ''; <p>SET UNIQUE_CHECKS = 0; START TRANSACTION;</p><p>WHILE i </p><pre class="brush:php;toolbar:false;">SET i = i + batch_size;
END WHILE;
COMMIT; SET UNIQUE_CHECKS = 1; END$$ DELIMITER ;
比存储过程更推荐的替代路径
如果目标只是「快速灌入百万测试数据」,存储过程反而是最绕的路:
-
LOAD DATA INFILE:本地文件导入,实测 100 万行通常 - 客户端批量提交:Python/Java 用
executemany()或 JDBCrewriteBatchedStatements=true,可控性更强 - CTE 递归生成(MySQL 8.0+):
WITH RECURSIVE ... INSERT SELECT,无磁盘依赖,纯 SQL 完成
存储过程适合封装逻辑、复用调用,但不适合扛原始吞吐压力 —— 它的语法限制、调试困难、错误堆栈模糊,会让定位 max_allowed_packet 超限或字符集截断这类问题变得极其痛苦。










