LOAD DATA INFILE 导入千万行CSV需突破三重安全限制:secure_file_priv路径白名单、local_infile服务端开关、客户端allowLoadLocalInfile启用;路径须纯英文、CSV须UTF-8无BOM编码;导入后必须用COUNT(*)实测行数并抽样验证。

能直接用 LOAD DATA INFILE 导入千万行 CSV,但“安全”不等于“开箱即用”——它默认会跳过错误、忽略约束、拒绝中文路径,且权限链路上有三道关卡必须手动打通。
为什么 LOAD DATA INFILE 一执行就报错 ERROR 3948 或 ERROR 2068
这不是语法问题,是 MySQL 的双重安全拦截机制在起作用:
-
secure_file_priv不为空(比如值为C:/ProgramData/MySQL/Uploads/):MySQL 只允许从该目录读取文件,哪怕你写的是绝对路径也没用 -
local_infile是OFF:客户端连接时未开启本地文件加载能力,LOAD DATA LOCAL INFILE直接被拒 - DBeaver/Navicat/命令行客户端没显式启用
allowLoadLocalInfile=true:即使服务端开了,客户端仍会拦截
验证方式:SHOW VARIABLES LIKE '%secure_file_priv%'; 和 SHOW VARIABLES LIKE 'local_infile'; 必须同时为非空值 + ON。
CSV 文件路径和编码的硬性限制
Windows 下常见陷阱不是语法写错,而是路径或编码“看起来对、实际错”:
- 路径中含中文、空格、括号(如
C:\Users\张三\Downloads\data.csv)→ 必报错,必须改用纯英文路径,例如C:/tmp/data.csv - CSV 是 ANSI 或 GBK 编码 → 即使指定了
CHARACTER SET utf8mb4,导入后中文仍是问号;必须用 Notepad++ 或 VS Code 转存为 UTF-8 无 BOM 格式 - 字段含换行符或双引号 → 若没加
ENCLOSED BY '"',会导致列错位甚至中断导入
推荐预处理命令(Linux/macOS):iconv -f gbk -t utf-8 input.csv | sed 's/"/""/g' > output.csv,Windows 用户优先用 Notepad++ 批量转码。
导入前必须做的三件事(跳过任一都会丢数据)
大文件导入不是“建好表就开干”,而是要主动控制校验粒度:
- 先建表时所有字段设为
VARCHAR+NULL,别急着加NOT NULL或主键——CSV 里空值、格式错位太常见 - 导入命令里加上
IGNORE 1 LINES(跳过表头)和CHARACTER SET utf8mb4,避免第一行当数据、乱码当脏数据 - 加
SET @dummy = NULL类似占位逻辑(可选),或用INSERT IGNORE配合 staging 表做二次清洗,而不是依赖LOAD DATA INFILE一次性搞定所有业务逻辑
典型安全导入语句:LOAD DATA LOCAL INFILE 'C:/tmp/data.csv' INTO TABLE raw_staging FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES (col1, col2, col3);
真正影响“安全”的其实是导入后的验证动作
很多人以为执行完没报错就成功了,但 LOAD DATA INFILE 默认静默跳过非法行(比如类型不匹配、超长字符串),只靠 SHOW WARNINGS 查看不够直观:
- 导入后立刻查:
SELECT COUNT(*) FROM raw_staging;对比 CSV 行数(用wc -l或 Excel 全选计数) - 抽样检查空值比例:
SELECT COUNT(*) FROM raw_staging WHERE col1 IS NULL;,若远高于预期,说明分隔符识别失败 - 用
SELECT * FROM raw_staging WHERE col1 REGEXP '[^[:ascii:]]' LIMIT 5;快速定位编码残留问题
最易被忽略的一点:千万行导入后,INFORMATION_SCHEMA.TABLES 中的 TABLE_ROWS 是估算值,不准;必须用 COUNT(*) 实测,否则你以为导了 800 万,其实只有 300 万。











