load data infile 是最快路径,但受 secure_file_priv 硬性限制,必须将 csv 放入指定目录;字段顺序与类型须严格匹配,推荐先导入 text 表再清洗;批量插入需分事务、关约束检查、清 bom。

LOAD DATA INFILE 是最快路径,但 secure_file_priv 不是可选配置
它不是“建议开启”,而是硬性开关:如果 SHOW VARIABLES LIKE 'secure_file_priv' 返回 NULL 或空字符串,LOAD DATA INFILE 直接报错 ERROR 1290 (HY000)。你必须把 CSV 文件放到它指定的目录里(比如 /var/lib/mysql-files/),不能靠改路径绕过。
常见错误现象:
- 用绝对路径写
LOAD DATA INFILE '/home/user/data.csv'→ 报错 “The used command is not allowed with this MySQL version” - 误以为加
LOCAL就能本地读 → 忘了服务端要开local_infile=ON,且客户端连接时得显式启用PDO::MYSQL_ATTR_LOCAL_INFILE => true
安全做法是:先确认路径,再 scp 或 mv 文件过去,别图省事用符号链接——MySQL 默认不跟随 symlinks。
字段顺序和类型不匹配会导致静默丢行或报错 Incorrect integer value
CSV 第一列必须对应表的第一字段,类型也得对得上。比如 CSV 里某行写的是 "abc",123,而表定义是 id INT, name VARCHAR(20),就会报 Incorrect integer value: 'abc';但如果反过来,name 是第一字段、id 是第二字段,那 "abc" 会被塞进 id,触发转换失败。
避免方式:
- 建表时字段顺序严格按 CSV 列顺序来,别靠
SET col1 = @1, col2 = @2映射——这只能补救,不能解决 NULL/类型冲突 - 导入前用
head -n 5 data.csv看真实字段顺序,别信文件名或文档描述 - 宽表暂存策略更稳:先建全
TEXT字段的raw_import表,成功导入后再用INSERT SELECT转到目标表做类型校验和清洗
批量 INSERT 每批别超 5000 行,且禁用 ON DUPLICATE KEY UPDATE
单条 INSERT INTO t VALUES (),(),...; 看似简单,但受 max_allowed_packet 和锁粒度双重限制。默认 4MB 包大小,含中文的 5000 行 CSV 很容易超限,报错 Packets larger than max_allowed_packet are not allowed。
性能陷阱:
- 加
ON DUPLICATE KEY UPDATE后,每行都触发唯一索引查找,速度下降 30% 以上 - 不显式开事务,每条语句自动提交 → 多次刷盘 + binlog 写入,I/O 压力翻倍
- 用
REPLACE INTO更糟:先 DELETE 再 INSERT,可能引发外键级联删除意外清空关联数据
实操底线:$pdo->beginTransaction() 包裹 array_chunk($rows, 5000),用预处理 INSERT INTO t (a,b) VALUES (?,?),别拼 SQL 字符串。
InnoDB 导入前关检查比删索引更有效
很多人想当然地执行 ALTER TABLE t DISABLE KEYS,但这对 InnoDB 无效——它只作用于 MyISAM。真正该关的是约束检查:
-
SET unique_checks = 0:跳过唯一索引重复校验(导入后记得=1并ANALYZE TABLE) -
SET foreign_key_checks = 0:避免逐行校验外键,尤其多表关联导入时 - 别动
autocommit:InnoDB 的 autocommit 关闭后,大事务反而更容易 OOM 或锁表太久
这些设置是 session 级的,只影响当前连接,导入完立刻恢复。比临时删索引安全得多,也不会在崩溃后留下损坏索引。
最易被忽略的一点:字符集。UTF-8 CSV 如果带 BOM(EF BB BF),LOAD DATA INFILE 会把 BOM 当成第一列内容,导致所有字段偏移。导入前先用 sed -i '1s/^\xEF\xBB\xBF//' data.csv 清掉。











