如何在MySQL中优雅地批量插入数据并避免超时?

小磊吖_4194

小磊吖_4194

2026-10-26

616人浏览

原创

单条INSERT VALUES建议每批500–2000行,对应SQL长度100KB–2MB,需规避max_allowed_packet限制、解析耗时及连接池超时;MyBatis需分段提交而非仅设BATCH模式;并发插入须应用层去重、ID预分配、每批独立事务;关键配置需调优innodb_flush_log_at_trx_commit=2、bulk_insert_buffer_size≥64M、max_allowed_packet≥256M。

如何在mysql中优雅地批量插入数据并避免超时?

单条 INSERT VALUES 能塞多少行才不超时

MySQL 本身不限制 VALUES 后面写几组数据,但实际能塞多少,取决于三个硬性限制:网络传输上限、SQL 解析耗时、服务端配置。最常卡住的是 max_allowed_packet(默认 64MB),一旦拼出的 SQL 超过这个值,直接报错 Packets larger than max_allowed_packet are not allowed;其次是 JDBC 驱动或连接池的 queryTimeout,比如 HikariCP 默认 30 秒,拼了 10 万行进去,解析+执行很容易超。

实操建议:

  • 每批控制在 500–2000 行之间,对应 SQL 长度约 100 KB – 2 MB,兼容大多数配置
  • 上线前用 SELECT LENGTH(?) 测下拼出来的 SQL 字节数,别只数行数
  • 如果必须插更多,优先考虑 LOAD DATA INFILE,它绕过 SQL 解析层,快一个数量级

MyBatis 批量插入超时,光设 ExecutorType.BATCH 不够

很多人以为只要 openSession(ExecutorType.BATCH) 就万事大吉,结果还是超时——因为 MyBatis 的 BATCH 模式只是把 SQL 缓存在内存里,真正发出去前仍要拼成一条巨长的 INSERT INTO ... VALUES (),(),()...。如果 list 有 5 万条,它就真给你拼 5 万个括号,不超时才怪。

关键动作是「分段提交」:

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • 循环中每累计 500 条调一次 mapper.insert(),然后手动 session.flushStatements()
  • 避免用 <foreach></foreach> 一次性生成超长 SQL,改用 Java 层分批构造 INSERT 语句
  • 确认数据源配置里 queryTimeout 设到了足够值(如 600 秒),否则连接池先杀请求

并发批量插入时主键冲突和锁等待怎么破

高并发下多个线程同时跑批量插入,哪怕每批都用事务包着,也容易在唯一索引字段(比如 order_no)上抢锁,出现 Lock wait timeout exceeded 或死锁。这不是“加个索引”能解决的,得从数据源头控重和 ID 分配逻辑入手。

必须做的三件事:

  • 应用层去重:插入前用 Map<string object></string> 或 Set<string></string> 过滤重复的业务唯一键(如 device_id),别指望数据库报错再 catch
  • 自增 ID 预分配:不用 SELECT MAX(id)(会串行化),改用 REPLACE INTO 或提前申请 ID 段(如 INSERT INTO seq VALUES () + LAST_INSERT_ID())
  • 每批独立事务:START TRANSACTION; INSERT ... ; COMMIT; 包住整批,不要跨批共用一个事务,否则一个失败全滚,重试成本爆炸

哪些 MySQL 配置不调,批量插入永远快不起来

就算 SQL 写得再好,innodb_flush_log_at_trx_commit=1 和默认的 bulk_insert_buffer_size=8M 也会把你拖回石器时代。这些参数不是“可选优化项”,而是批量写入的基础设施。

上线前必查:

  • innodb_flush_log_at_trx_commit=2:牺牲极小概率的崩溃丢失(非 0),换取日志刷盘性能翻倍
  • bulk_insert_buffer_size 调到 64M 或更高(需配合可用内存),专为 INSERT ... SELECT 和多值 INSERT 加速
  • max_allowed_packet 至少设为 256M,否则拼大 SQL 直接被拒
  • 批量前临时 ALTER TABLE t DISABLE KEYS,插完再 ENABLE,对 MyISAM 有效,InnoDB 无效但无害
批量插入真正的复杂点不在“怎么写 SQL”,而在于你是否清楚每一步操作在 InnoDB 层触发了什么:MVCC 版本链怎么建、聚簇索引页怎么分裂、undo log 怎么记、redo log 怎么刷。这些细节不会报错,但会让同样 10 万行数据,执行时间差出 10 倍。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2353

6

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.21

1439

5

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

855

5

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.19

3292

5

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.25

5628

4

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.08

1239

3

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

5891

4

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

2023.08.14

5122

7

mysql事务隔离级别
mysql事务隔离级别

mysql规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。本专题为大家提供mysql事务隔离级别相关的文章内容,大家可以免费体验。

2023.08.16

6854

11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 191人学习