MySQL导入崩溃主因是innodb_buffer_pool_size超限或max_allowed_packet不足,需按物理内存50%~60%设缓冲池、调大packet值,并控制单次导入行数与VALUES括号量。
MySQL 导入时突然崩溃重启,大概率是 innodb_buffer_pool_size 超限或 max_allowed_packet 被击穿
mysql 在大批量导入(比如 load data infile 或大事务 insert)时崩溃重启,不是磁盘满、也不是权限错,八成是内存被撑爆了。innodb 缓冲池吃掉主内存大头,而单条 sql 包体过大又会卡在解析阶段——这两处一叠加,mysqld 进程直接被 oom killer 杀掉,日志里能看到 killed process 或 out of memory。
实操建议:
- 检查崩溃前最后一条导入语句:如果它包含超长文本字段(如 JSON、base64)、或单次插入上万行,优先怀疑
max_allowed_packet不够(默认 4MB),需在my.cnf中调大,例如max_allowed_packet = 256M,改完必须重启 MySQL - 用
free -h和ps aux --sort=-%mem | head -5确认系统是否真内存不足;若mysqld占用接近innodb_buffer_pool_size设置值,且该值超过物理内存的 70%,就危险了 - 不要盲目调高
innodb_buffer_pool_size—— 它不是越大越好。Linux 下若设置过高,会导致 swap 频繁或直接触发 OOM。稳妥做法是设为物理内存的 50%~60%,并预留至少 2GB 给系统和其他进程
LOAD DATA INFILE 单次导入多少行最稳?别信“10 万行”,看数据宽度和索引数量
所谓“单次 10 万行安全”,只在纯数字、无索引、无外键的宽表上可能成立。真实业务表往往带多个二级索引、TEXT 字段、触发器,每行实际内存开销可能是表面上的 3–5 倍。MySQL 内部会为每行构建临时索引项、维护 undo log、计算 checksum,批量越大,锁持有时间越长,buffer pool 压力越陡峭。
实操建议:
- 用
SHOW CREATE TABLE查清表结构:每多一个二级索引,单行写入成本线性上升;有FULLTEXT或SPATIAL索引,务必把批量降到 5k 行以内 - 导入前临时禁用非必要索引:
ALTER TABLE t1 DISABLE KEYS(仅 MyISAM 有效)不适用于 InnoDB;InnoDB 正确做法是删掉次要索引,导入完成再重建 - 按列宽估算单行体积:比如一行含 3 个
VARCHAR(2000)+ 1 个TEXT,平均占 8KB,那 5 万行 ≈ 400MB 内存压力 —— 已逼近多数 16GB 服务器的安全阈值
用 INSERT ... VALUES (),(),... 批量插入时,括号数不是越多越好
很多人以为拼得越长越快,结果发现 10 万组 () 一执行就卡死甚至崩溃。问题不在行数,而在 MySQL 解析器对单条语句的 token 数和内存分配有隐式限制。过长的 VALUES 列表会让解析器在构建语法树阶段就耗尽栈空间,报错类似 ERROR 139 或直接断连。
实操建议:
- 单条
INSERT的VALUES括号数控制在 1000–5000 之间较稳妥;具体上限取决于字段数:10 列以下可用 5000,20 列以上建议压到 1000 - 避免在语句中混用函数或子查询(如
NOW()、(SELECT id FROM t2 WHERE ...)),它们会让优化器放弃批量优化路径,退化成逐行处理 - 用
mysql --local-infile=1配合LOAD DATA,比拼接INSERT快 5–10 倍,且内存更可控 —— 因为数据流式读取,不全加载进 SQL 解析器
导入中途崩溃后怎么续传?别依赖 AUTO_INCREMENT,用显式位点+唯一约束兜底
靠 LAST_INSERT_ID() 或查最大 ID 续传,看似简单,实则埋雷:并发写入、删除、手动插入都会让 ID 不连续;更糟的是,如果崩溃发生在事务提交前,部分行已落盘但事务未提交,重跑会报 Duplicate entry 错误却无法判断哪些已成功。
实操建议:
- 导入前加个状态字段,比如
import_status TINYINT DEFAULT 0(0=未导入,1=已导入),每次插入都带ON DUPLICATE KEY UPDATE import_status = VALUES(import_status),避免重复失败 - 用文件偏移或行号做位点:把 CSV 每行加序号,导入脚本记录最后成功处理的行号,下次从该行继续;比依赖数据库自增更可靠
- 确保目标表有唯一约束(如业务主键或组合唯一索引),否则续传时无法识别重复,容易脏数据
真正麻烦的不是崩一次,而是崩在没开 binlog 或没设 innodb_flush_log_at_trx_commit = 1 的实例上——这时候连崩溃前最后几秒的数据都可能丢失,恢复只能靠原始文件重放。别省这点 IO 开销。










