SQL 如何批量插入 10 万条数据不卡死事务

发布时间 - 2026-01-30 00:00:00    点击率:
直接 INSERT INTO VALUES 卡死因每条语句默认独立事务,10万次引发频繁redo写盘、B+树分裂、锁竞争与日志阻塞;应改用批量VALUES+禁用autocommit+分批提交,并关闭unique_checks和foreign_key_checks。

为什么直接 INSERT INTO VALUES 会卡死?

因为每条 INSERT INTO ... VALUES (...) 默认是独立事务,10 万次就是 10 万次日志写入、锁竞争和事务开销。尤其在 InnoDB 下,频繁提交会触发大量 redo log 刷盘和索引 B+ 树分裂,CPU 和 I/O 都会打满。

常见现象:Lock wait timeout exceededMySQL server has gone away、客户端长时间无响应。

  • 单条插入耗时通常 >10ms(含网络+解析+执行+提交),10 万条 ≈ 16 分钟,远超默认 wait_timeout(通常 28800 秒但连接可能提前中断)
  • 事务日志(redo log)可能填满 active log space,导致写阻塞
  • 唯一索引或外键检查逐条进行,无法批量跳过中间校验

用 INSERT INTO ... VALUES (...), (...), (...) 批量拼接

这是最简单有效的提速方式,把多行数据合并进一条语句,大幅减少 SQL 解析、权限校验和事务开销。

实操建议:

  • 每批控制在 1000–5000 行之间(取决于单行数据长度;总 SQL 长度别超 max_allowed_packet,默认 4MB)
  • 避免在循环里拼字符串累加,改用数组收集后 join()StringBuffer 构建
  • 示例(Python + PyMySQL):
    values = [(1,'a'),(2,'b'),(3,'c')]  
    sql = "INSERT INTO t (id, name) VALUES " + ",".join(["%s"] * len(values))  
    cursor.execute(sql, values)
  • 注意:所有值必须统一类型,NULL 要显式写成 None(Python)或 NULL(SQL 字符串中)

配合禁用自动提交 + 手动 COMMIT 控制事务粒度

即使用了批量 VALUES,如果每次 execute 后都自动 commit,还是等于 100 次事务(假设分 100 批)。必须关掉 autocommit,自己控制 commit

时机。

  • MySQL 连接初始化时设 autocommit=False(PyMySQL/MySQLdb)或 connection.autocommit(False)
  • 每 5000–10000 行 commit 一次:太小 → 事务开销没降够;太大 → rollback 成本高、锁持有太久
  • 务必在 finally 块里 connection.rollback(),防止异常后连接卡在未提交状态
  • 注意:SET autocommit = 0 是会话级,但 ORM(如 SQLAlchemy)可能覆盖它,优先用驱动原生接口

其他关键优化点(容易被忽略)

光靠拼 SQL 和调事务还不够,下面几项不处理,依然可能卡住或失败。

  • 临时关闭唯一性检查:SET unique_checks = 0(导入完记得设回 1),否则每行都走唯一索引查找
  • 暂停外键约束:SET foreign_key_checks = 0,适用于你确定数据合规的场景
  • 确认 innodb_log_file_size 足够大(建议 ≥1GB),否则小 log file 会频繁 checkpoint,拖慢写入
  • 如果表有二级索引,考虑先删索引、插完再重建(DROP INDEX + CREATE INDEX),比边插边维护快 3–5 倍
  • 不要用 LOAD DATA INFILE 除非文件在数据库服务器本地——它虽最快,但权限和路径限制多,且无法做应用层数据转换

批量插入不是“拼得越多越好”,而是要在单语句长度、事务大小、日志压力、索引维护成本之间找平衡点。最容易被忽略的是 unique_checksforeign_key_checks 这两个会话变量,它们默认开启,会在每一行都触发额外的索引扫描,10 万行下性能折损常超 40%。


# mysql  # python  # go  # ai  # 为什么  # red  # sql  # NULL  # 字符串  # 循环  # 接口  # finally  # 数据库  # 每条  # 的是  # 这是  # 长时间  # 会在  # 要在  # 这两个  # 用了  # 太大  # 越多 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 北京企业网站设计制作公司,北京铁路集团官方网站?  如何快速搭建高效服务器建站系统?  教学论文网站制作软件有哪些,写论文用什么软件 ?  为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】  网页制作模板网站推荐,网页设计海报之类的素材哪里好?  php结合redis实现高并发下的抢购、秒杀功能的实例  高性能网站服务器部署指南:稳定运行与安全配置优化方案  JavaScript如何实现继承_有哪些常用方法  简历在线制作网站免费版,如何创建个人简历?  活动邀请函制作网站有哪些,活动邀请函文案?  1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤  如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  php485函数参数是什么意思_php485各参数详细说明【介绍】  香港服务器租用每月最低只需15元?  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  音响网站制作视频教程,隆霸音响官方网站?  php在windows下怎么调试_phpwindows环境调试操作说明【操作】  Laravel如何配置任务调度?(Cron Job示例)  用yum安装MySQLdb模块的步骤方法  如何快速建站并高效导出源代码?  电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  如何在 Pandas 中基于一列条件计算另一列的分组均值  Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?  JavaScript如何实现路由_前端路由原理是什么  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  Laravel怎么自定义错误页面_Laravel修改404和500页面模板  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  Laravel如何处理异常和错误?(Handler示例)  Laravel模型关联查询教程_Laravel Eloquent一对多关联写法  Laravel distinct去重查询_Laravel Eloquent去重方法  宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法  Laravel中的Facade(门面)到底是什么原理  如何快速查询域名建站关键信息?  C++用Dijkstra(迪杰斯特拉)算法求最短路径  标题:Vue + Vuex + JWT 身份认证的正确实践与常见误区解析  Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲  魔毅自助建站系统:模板定制与SEO优化一键生成指南  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  如何在VPS电脑上快速搭建网站?  Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)  javascript事件捕获机制【深入分析IE和DOM中的事件模型】  详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点  JS经典正则表达式笔试题汇总  Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程  Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用  Laravel如何实现API资源集合?(Resource Collection教程)