如何将CSV数据批量导入数据库_LOAD DATA INFILE与并行导入

2次阅读

LOAD DATA INFILE 无法导入本地文件是因为 MySQL 服务端未启用 local_infile=ON 且客户端未显式允许;需修改 my.cnf 并重启服务,连接时加 –local-infile= 1 或 pymysql 中设 local_infile=True。

如何将 CSV 数据批量导入数据库_LOAD DATA INFILE 与并行导入

LOAD DATA INFILE 为什么导入不了本地文件?

MySQL 默认禁用 LOAD DATA INFILE 读取客户端本地路径,报错通常是 ERROR 1148 (42000): The used command is not allowed with this MySQL configuration 或直接提示文件不存在——哪怕文件明明在你电脑上。

根本原因不是权限不够,而是服务端配置没开:MySQL 服务端必须启用 local_infile=ON,且客户端连接时也要显式允许。光改 my.cnf 不够,还要确认连接参数。

  • 服务端:在 /etc/mysql/my.cnf(Linux)或 my.ini(Windows)的 [mysqld] 段加 local_infile=ON,然后重启 mysqld
  • 客户端:用 mysql --local-infile=1 -u root -p 连接;如果用 Python 的 pymysql,初始化连接时要加 local_infile=True
  • 安全限制:某些托管数据库(如阿里云 RDS、AWS RDS)默认禁用且不可修改,此时 LOAD DATA INFILE 直接不可用

CSV 字段乱码、截断、NULL 值识别失败

看似是数据问题,其实是字段分隔符、行结束符和 NULL 处理策略不匹配导致的。MySQL 不会自动猜编码或空值格式,所有解析行为都由 LOAD DATA INFILE 的子句严格控制。

常见现象:中文变问号、最后一列总少一位、数字字段出现 NULL 却被当成字符串 "NULL"

  • 编码必须显式指定:CHARACTER SET utf8mb4(别用 utf8,它不支持 emoji)
  • 字段分隔符默认是 t,不是逗号!要导 CSV 必须写 FIELDS TERMINATED BY ','
  • 文本包裹符很关键:如果 CSV 有逗号在引号内(如 "Smith, John",25),必须加 OPTIONALLY ENCLOSED BY '"'
  • 空字符串转 NULL:加 SET col_name = NULLIF(col_name, ''),否则空字符串会被存成 '' 而非 NULL

并行导入 ≠ 同时跑多个 LOAD DATA INFILE

MySQL 的 LOAD DATA INFILE 是表级锁(InnoDB 下为意向排他锁 + 行锁),并发执行多个会排队,甚至因锁等待超时失败。所谓“并行”,实际是指把大 CSV 拆成小块,再用不同连接、不同目标表(或分区)分散处理。

真正在用的方案只有两种:预分片 + 多连接,或先入库临时表再合并。

  • 拆文件:用 split -l 100000 data.csv chunk_ 分割,再用 shell 循环启动多个 mysql 进程,各自导入不同 chunk 到同一张表(注意:需确保表无唯一键冲突)
  • 多表中转:建若干临时表(如 tmp_import_1, tmp_import_2),分别导入,再用 INSERT INTO main_table SELECT * FROM tmp_import_1 等语句合并
  • 跳过索引加速:导入前执行 ALTER TABLE t DISABLE KEYS,导入完再 ENABLE KEYS(仅对 MyISAM 有效;InnoDB 请关掉唯一约束校验或用 SET unique_checks=0

替代方案比硬刚 LOAD DATA INFILE 更省心

当遇到云数据库限制、字段逻辑复杂(比如需要清洗、映射、关联查证)、或导入频率高需自动化时,LOAD DATA INFILE 反而成为瓶颈。这时候直接走应用层批量插入更可控。

例如 Python + pymysql:用 executemany() 批量提交,配合 cursor.executemany("INSERT INTO t VALUES (%s,%s)", rows),每批 1000–5000 行,比单条快 10–50 倍;若再加 INSERT IGNOREON DUPLICATE KEY UPDATE,还能天然防重。

  • 不要低估网络开销:千兆内网下,纯 SQL 导入 100 万行约 3–8 秒;Python 批量插入约 10–20 秒,但可嵌入清洗逻辑、日志、重试、监控
  • PostgreSQL 用户注意:COPY 命令性能接近 MySQL 的 LOAD DATA,但它也要求服务端文件路径或启用 client_encoding 显式设为 UTF8
  • 真正的大数据量(千万级以上):别卡在单机导入,考虑用 mysqldump --tab 输出 + LOAD DATA 配合,或迁移到 ClickHouse / Doris 做前置 ETL

最常被忽略的一点:CSV 文件本身是否真正合规——有没有隐藏的 BOM 头、混合换行符(rnn 并存)、Excel 自动加的双引号逃逸错误。这些都会让 LOAD DATA INFILE 在第 8372 行突然失败,且报错信息完全不提具体哪一行。建议先导一份前 100 行做验证。

text=ZqhQzanResources