单条INSERT在千万级场景下必然卡死,因其每条都要重复执行网络往返、SQL解析、redo/undo日志写入、B+树分裂及binlog落盘,1000万次即1000万遍开销,导致磁盘IO与锁竞争拉满;实测单条插入10万行平均5.2ms/条,批量优化后可降至0.05ms/条。

为什么单条INSERT在千万级场景下必然卡死
因为每条INSERT都要走完整链路:网络往返 + SQL解析 + redo log写入 + undo log生成 + 索引B+树分裂 + binlog落盘。1000万次就是1000万遍,磁盘IO和锁竞争直接拉满。实测中,单条插入10万行平均耗时5.2ms/条;批量优化后可压到0.05ms/条——差两个数量级不是玄学,是路径开销的硬差距。
必须调整的MySQL服务端参数
不调参就写批量SQL,等于开着拖拉机跑高速。关键几项必须改:
-
innodb_flush_log_at_trx_commit = 0:关闭每次事务强制刷盘,允许丢失最近1秒数据(仅限导入期临时启用) -
sync_binlog = 0:禁用binlog同步,主从延迟容忍期内可用 -
innodb_buffer_pool_size设为物理内存的60%~70%,避免频繁刷脏页 -
max_allowed_packet至少调到64M,否则INSERT INTO ... VALUES (...),(...),...会报Packet too large
注意:innodb_doublewrite = OFF虽能提速,但崩溃恢复风险陡增,生产环境慎用;建议只在离线导入专用实例中开启。
应用层批次大小怎么定
不是越大越好。字段越宽、含BLOB/TEXT越多,单批次能塞的行数就越少。经验公式:批次大小 ≈ 1MB / 单行平均字节数。例如:
- 纯INT+VARCHAR(50)结构 → 每行约100B → 建议每批5000~10000行
- 含2个TEXT字段 → 每行约2KB → 建议每批500~1000行
- 字段多且含JSON → 每行超5KB → 每批控制在200行内
超过阈值会导致MySQL服务端OOM或Packet too large错误,比慢还难排查。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
LOAD DATA INFILE比INSERT快的根本原因
它绕过了SQL解析器,直接把文件内容喂给InnoDB存储引擎。实测50万行CSV导入只要3~5秒,比最优INSERT ... VALUES快20倍以上。但有两个硬限制:
- 文件必须在数据库服务器本地,或开启
local_infile=ON并用LOAD DATA LOCAL INFILE - 需有
FILE权限,且受secure_file_priv路径白名单约束
如果你的数据在应用服务器上,又无法登录DB机器,LOAD DATA就不可用——这时候老老实实用executemany或addBatch/executeBatch,并确保JDBC连接串加rewriteBatchedStatements=true,否则MySQL驱动仍会拆成单条发送。
真正卡住千万级导入的,从来不是SQL怎么写,而是磁盘IO瓶颈、redo log刷盘频率、索引维护成本这三座大山。参数没调对,语法再漂亮也白搭。










