首页/数据/SQL 速查/批量导入:LOAD DATA 与 COPY
变更与事务52 条

批量导入:LOAD DATA 与 COPY

从文件批量装载数据:MySQL 用 LOAD DATA INFILE(服务端/客户端本地),PostgreSQL 用 COPY(服务端)或 \copy(客户端)。

SQL 速查数据更新于 2026-10-13

LOAD DATA 与 COPY 是什么

LOAD DATA 是 MySQL 把文本文件高速灌入表的方式,PostgreSQL 的对应语句是 COPY。共同点是不走逐条 INSERT 的往返开销,由服务端直接读文件批量写入,百万行级别通常比逐条插入快一个数量级。关键区别在文件位置与权限:MySQL 默认读服务器本地路径(需要 FILE 权限),加 LOCAL 关键字才读客户端文件,且要求服务端与客户端都开启 local_infile;PostgreSQL 的服务端 COPY 需要超级用户,而 psql 的 \copy 走客户端权限,普通账号也能用。

基本信息

MySQL 语句LOAD DATA [LOCAL] INFILE '路径' INTO TABLE 表 (列…)
PostgreSQL 语句COPY 表 (列…) FROM '路径' WITH (FORMAT csv, HEADER true)
权限要求MySQL 服务端读文件需 FILE 权限;PG 服务端 COPY 需超级用户,\copy 不需要
事务行为InnoDB 下失败可自动回滚;PG 的 COPY 可被事务包住整体回滚
典型速度百万行量级比逐条 INSERT 快约一个数量级,视索引与磁盘而定

典型使用场景

  • 初始化导入:把历史导出的大文件一次性灌进新表
  • 数据迁移:从旧库或上游系统导出的 CSV 批量搬入
  • 日志与埋点批量入库:每小时生成一个文件,定时任务导入
  • 测试数据准备:快速造百万级数据验证索引与查询性能
  • 整表恢复:与导出文件配合做单表级快速还原
  • 跨环境搬运:把生产抽样的部分数据导入测试库复现问题

MySQL 导入示例

MySQL 导入示例
LOAD DATA LOCAL INFILE '/tmp/orders.csv'      # LOCAL 表示文件在客户端机器上
INTO TABLE orders
CHARACTER SET utf8mb4                         # 显式声明,避免中文乱码
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'   # 处理带引号的字段
LINES TERMINATED BY '\n'
IGNORE 1 LINES                                # 跳过 CSV 表头
(@id, user_id, @amount, created_at)           # 先读进变量,便于清洗
SET id = @id, amount = REPLACE(@amount, ',', '');   # 去掉千分位后再入库

SHOW WARNINGS;                                # 立刻查看被跳过或截断的行

PostgreSQL 导入示例

PostgreSQL 导入示例
\copy orders (id, user_id, amount, created_at) FROM '/tmp/orders.csv' \  # psql 客户端侧执行
      WITH (FORMAT csv, HEADER true, NULL '');

-- 服务端 COPY 需要超级用户,可用事务保证失败整体回滚
BEGIN;
COPY orders FROM '/tmp/orders.csv' WITH (FORMAT csv, HEADER true);
COMMIT;

-- 导入后刷新统计,避免优化器按旧分布选计划
ANALYZE orders;

常见报错与处理

现象原因处理
secure-file-priv 报错服务端限制了可读目录把文件放到 secure_file_priv 目录,或改用 LOCAL 方式
中文乱码文件编码与 CHARACTER SET 不一致文件统一转 UTF-8,并在语句里显式声明 utf8mb4
日期列为 0000-00-00源数据格式不合法先读进变量,用 STR_TO_DATE 转换后再写入列
permission denied for filePG 服务端读文件权限不足改用 psql 的 \copy,让客户端负责读文件
列错位字段内含分隔符且未加引号写 OPTIONALLY ENCLOSED BY,或改用 TSV 分隔
LOAD DATA 支持把列先读进用户变量再用 SET 清洗,这是处理带千分位数字、空值标记(如 NULL 字符串、\N)最常用的手法,比事后 UPDATE 一遍更省时间。
导入前临时关闭唯一性检查(SET unique_checks=0)或外键检查(SET foreign_key_checks=0)能提速,但只有在确认数据干净时才能用,否则会写进重复键与孤儿行。

易错点

  • 忘了 IGNORE 1 LINES,表头行被当成数据,数值列报错或被截断成 0
  • 导入后不看 SHOW WARNINGS:被跳过的行静默丢失,语句显示成功但数据少了一部分
  • 未配置 secure_file_priv 就直接指向 /tmp 路径,权限报错;本地文件应改用 LOCAL 并在两端开启 local_infile
  • 百万行一次导入不做分批:长事务让 undo 与 binlog 膨胀,失败回滚代价也很高
  • CSV 字段内含逗号却没加引号,导致后续所有列整体错位而语句不报错

数据来源与参考

  • MySQL 8.0 Reference Manual · LOAD DATA
  • PostgreSQL Documentation · COPY
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌