pgloader 快速上手:一条命令把 CSV、SQLite、MySQL 与远程数据迁入 PostgreSQL

原创2026-10-03 21:33:581,710 阅读
文章标签:数据工程ETL数据集成数据库

pgloader 快速上手:一条命令把 CSV、SQLite、MySQL 与远程数据迁入 PostgreSQL

pgloader 是 PostgreSQL 生态中专注"迁移"的命令行工具,其核心理念是"Migrate to PostgreSQL in a single command"。本文基于仓库中的 docs/quickstart.rst 编写,覆盖最常用的快速路径:命令行直接加载 CSV、从标准输入(STDIN)读取数据、加载 HTTP 远程文件、流式解压远程归档,以及 SQLite / MySQL 整库迁移和远程 DBF 归档导入。读完本文,你将掌握 pgloader 两种驱动模式中最简单的一种——完全由命令行参数驱动(SOURCE TARGET 双参数模式),并理解每条命令背后的源码实现与适用前提。

一、两条使用路径:命令文件与命令行直驱

pgloader 提供了两种使用方式,理解它们的区别是快速上手的关键:

  • 命令文件(.load):pgloader 实现了一套类 SQL 的领域专用语言(DSL),支持 LOAD ... FROM ... INTO ... WITH ... 等子句,适合复杂场景(计算列、数据清洗、BEFORE/AFTER LOAD 钩子)。语法骨架见 docs/command.rst。
  • 命令行直驱:当只有一个源和一个目标、且逻辑足够简单时,可以直接把信息放在命令行上,完全绕过命令文件。

从 入口实现 可以看到,当命令行参数恰好是两个时(= 2 时),pgloader 会调用 process-source-and-target 把两个参数分别当作 SOURCE 和 TARGET 处理;而当参数多于两个时,则会把第一个参数当作命令文件(.load)解析。也就是说:

pgloader [ option ... ] SOURCE TARGET

这种"恰好两个参数"的模式就是快速入门的核心。命令行上没有命令文件,因此 --type、--field、--with 这些开关承担了传递额外信息的工作。

二、CSV 文件加载:最基础的入门命令

最简单的用例是把一个 CSV 文件加载到数据库里已经存在的表中:

pgloader --type csv                                   \
         --field id --field field                     \
         --with truncate                              \
         --with "fields terminated by ','"            \
         ./test/data/matching-1.csv                   \
         postgres:///pgloader?tablename=matching

逐项拆解这条命令:

  • --type csv:强制指定源类型。命令行模式下 pgloader 需要知道如何解析源,--type 是可选的"Force input source type"(见 main.lisp 选项定义)。CSV 文件没有内建的可探测类型,因此通常必须显式给出。
  • --field id --field field:声明源文件里每个字段的名字。--field 是可重复选项(list t),每出现一次声明一个字段,顺序与文件中的列一一对应。除了 --field id --field field 这种逐个声明的方式,也可以把多个字段名用逗号合并进一个参数,如 --field "usps,geoid,aland,awater"。
  • --with truncate:加载前对目标表执行 TRUNCATE,保证目标表从空表开始(详见下文"WITH 选项速查")。
  • --with "fields terminated by ','":指定 CSV 分隔符为逗号。
  • ./test/data/matching-1.csv:源文件,仓库中真实存在(见 test/data/matching-1.csv)。
  • postgres:///pgloader?tablename=matching:目标连接串。注意表名通过 URI 的 tablename 参数传递,且目标表必须已经存在、结构能与数据匹配。

--field 与 --with 的完整语法说明,见手册中的 CSV 参考文档。

从源码看,这条命令最终走的是 src/api.lisp 的 process-source-and-target:它解析源串、目标串,把 --with 通过 parse-cli-options 转成选项列表,把 --field 通过 parse-cli-fields 转成字段定义,最后统一调用 load-data 进入加载流程。这意味着命令行直驱与命令文件两种模式最终汇合到同一套加载管线,行为一致。

目标表必须预先存在

与 SQLite/MySQL 整库迁移不同,CSV 加载不会自动建表。手册中给出的配套建表 SQL 如下(这是快速入门文档中唯一一段 SQL,务必完整保留):

create table districts_longlat
(
         usps        text,
         geoid       text,
         aland       bigint,
         awater      bigint,
         aland_sqmi  double precision,
         awater_sqmi double precision,
         intptlat    double precision,
         intptlong   double precision
);

三、从 STDIN 读取:管道与流式处理的基石

文件类数据源也可以从标准输入读取,把 -(Unix 惯例中的标准输入)作为源参数即可:

pgloader --type csv                                         \
         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
         --with "skip header = 1"                          \
         --with "fields terminated by '\t'"                \
         -                                                 \
         postgresql:///pgloader?districts_longlat          \
         < test/data/2013_Gaz_113CDs_national.txt

与上一例的区别:

  • - 作为源:表示标准输入,数据由重定向 < 喂给 pgloader。
  • --field 一次声明全部 8 个字段:用逗号分隔字段名,避免多次 --field。
  • --with "skip header = 1":跳过文件第一行。该文件第一行通常是列名或版权说明,不能当作数据。测试数据 test/data/2013_Gaz_113CDs_national.txt 正是该例的源文件。
  • --with "fields terminated by '\t'":分隔符为制表符(\t 在单引号内表示 Tab)。

流式加载压缩文件

STDIN 模式最大的价值在于与 Unix 管道组合,实现"边下载边解压边导入":

gunzip -c source.gz | pgloader --type csv ... - pgsql:///target?foo

注意:源参数 - 前的 ... 表示完整的 --field/--with 参数集,实际执行时需按上例补全。操作系统负责网络与命令之间的流式缓冲,pgloader 负责把数据流持续灌入 PostgreSQL,全程无需落盘整个解压后的文件。

四、从 HTTP 加载 CSV:远程文件直接导入

CSV 文件位于远程 HTTP 地址时,pgloader 也能直接处理:

pgloader --type csv                                                     \
         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
         --with "skip header = 1"                                       \
         --with "fields terminated by '\t'"                             \
         http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt     \
         postgresql:///pgloader?districts_longlat

这条命令与 STDIN 一节的命令几乎完全相同,只是把源从 - 换成了 HTTP URL。再次强调:

  • 第一行是表头,所以需要 skip header = 1;
  • 全部字段合并进单个 --field 参数声明;
  • 目标连接串必须带 tablename 选项;
  • 目标表必须已存在且能容纳数据(即上一节的 districts_longlat 建表语句)。

另外,文档特别指出:同样的命令对同一份数据的归档版本(如 .gz)同样有效——pgloader 会在本地先抓取 HTTP 内容,识别出归档格式并解压,然后处理解压后的本地文件。

归档处理的实现细节

HTTP 抓取与解压的逻辑集中在 src/utils/archive.lisp:

  • http-fetch-file 负责把远程文件下载到本地临时目录(*default-tmpdir*);
  • 支持归档类型由 *supported-archive-types* 定义,为 :tar :tgz :gz :zip 四种;
  • archive-type 依据文件扩展名判定类型,expand-archive 分别调用 untar / gunzip / unzip 解压。

因此"下载 → 解压 → 打开 → 发现 schema → 加载数据"是 pgloader 对远程归档的默认完整流程。

五、流式解压远程压缩 CSV:curl + gunzip + pgloader

当你的归档格式 pgloader 不支持,或环境中无法展开归档时,可以用经典管道把内容直接流式送入 PostgreSQL:

curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \
| gunzip -c                                                        \
| pgloader --type csv                                              \
           --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
           --with "skip header = 1"                                \
           --with "fields terminated by '\t'"                      \
           -                                                       \
           postgresql:///pgloader?districts_longlat

这里 curl 从远程拉取 .gz 归档,gunzip -c 就地解压并输出到 stdout,pgloader ... - 从标准输入消费数据。OS 负责网络与命令进程间的流式缓冲,pgloader 则持续把数据流式写入 PostgreSQL。相比上一节的"先抓取再解压再处理",这种方式节省了中间落盘步骤,是处理大规模远程归档的推荐手法。

六、SQLite 整库迁移:schema 自动发现与类型转换

SQLite 迁移只需两条命令:

createdb newdb
pgloader ./test/sqlite/sqlite.db postgresql:///newdb

pgloader 会打开 SQLite 数据库,自动发现其表结构、索引与外键,把这些定义**cast(转换)**为 PostgreSQL 等价类型后迁移过来,随后迁移数据。仓库中 test/sqlite/ 下提供了真实可用的样例库(如 test/sqlite/sqlite.db、Chinook 样例),可以拿来直接体验。

源码佐证:

与 CSV 不同,SQLite/MySQL 迁移时源是"数据库"而非"文件",pgloader 能自行探测 schema,因此不需要 --type,也不需要预先建表。

七、MySQL 整库迁移:一行命令完成

MySQL 迁移同样是一条命令的事:

createdb pagila
pgloader mysql://user@localhost/sakila postgresql:///pagila

pgloader 连接 MySQL 的 sakila 库,自动迁移其表结构(含索引、外键、视图等可迁移对象)、cast 数据类型并搬运数据。仓库中提供了完整可复现的测试场景,例如 tests/mysql/sakila 与 test/mysql 目录下的 .load 与 .sql 文件。

实现要点:MySQL 侧的类型转换规则见 src/sources/mysql/mysql-cast-rules.lisp,连接与 schema 探测在 src/sources/mysql/mysql-connection.lisp 与 src/sources/mysql/mysql-schema.lisp 中,源类型到加载代码的分派表定义于 src/api.lisp。

八、远程 DBF 归档:下载 → 解压 → 探测 → 导入

最后一个快速用例是 DBF(dBase)文件。pgloader 可以从 HTTP 下载归档、解压、打开并探测 schema,然后加载数据:

createdb foo
pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo

这里必须使用 --type dbf:与 CSV 类似,pgloader 无法从给定的 HTTP URL 猜出数据源类型,因此需要命令行开关显式指定。仓库中的 DBF 测试数据与用例见 tests/dbf(含 dbf-31、dbf-8b、dbf-memo、reg2013 等场景)。

九、WITH 选项速查:快速路径可用的常用开关

命令行直驱模式下,--with 是可重复的"Load options"(main.lisp),其解析器会把它映射为与命令文件 WITH 子句等价的选项。从 CSV 参考文档 与 CSV 解析器实现 可以确认,快速入门中最常用的包括:

选项 作用
truncate 加载前对目标表执行 TRUNCATE,清空旧数据
skip header = N 跳过输入文件开头的 N 行(表头/版权行)
csv header 把跳过表头后的第一行当作 CSV 字段名列表
fields terminated by 'X' 设置字段分隔符,支持普通字符、\t、0xNN 十六进制形式
lines terminated by 'X' 设置行结束符
fields optionally enclosed by 'X' 设置引用/包围字符(默认双引号),如 '\'' 或 '0x27'
fields not enclosed 字段不加引号,双引号按普通字符处理
fields escaped by backslash-quote 设置转义字符
csv escape mode quote / following 控制转义解析模式(默认 quote)
trim unquoted blanks / keep unquoted blanks 是否裁掉未加引号字段两侧的空白(默认裁剪)
date format '...' 为日期/时间类型列统一指定解析模板
on error stop / on error resume next 出错即停 / 出错继续
batch rows = R、batch size = ... MB、prefetch rows = ... 批量行为控制
workers = W、concurrency = C、max parallel create index = I 并行度控制

分隔符与引号字符的解析规则在 command-csv.lisp 中有精确定义:支持 \t 表示制表符、\ 表示反斜杠、0x 加两位十六进制表示 ASCII 码,以及单引号转义写法。

十、命令行直驱的适用边界与注意事项

综合源码与文档,使用快速路径时请注意以下几点:

  1. 只有恰好两个位置参数时才会走 SOURCE TARGET 快速模式;否则第一个参数会被当作 .load 命令文件解析(main.lisp)。
  2. --type 的适用性:CSV、DBF 等文件型源通常必须显式 --type;SQLite/MySQL 这类数据库源可自动识别。
  3. 目标表存在性:CSV 加载要求目标表已存在且结构匹配;SQLite/MySQL 迁移则由 pgloader 自动建表。
  4. 表名传递:文件型源的目标表名通过 PostgreSQL 连接串的 tablename 参数指定,可以带 schema 前缀(如 ?tablename=geolite.blocks)。
  5. 当命令行参数与命令文件混用时:--type、--with、--field 等选项在加载 .load 文件时会被忽略并给出提示(main.lisp),所以不要混用两种模式。

快速路径背后的统一入口 load-data(src/api.lisp)会把命令行解析结果编译为加载代码并执行;从 api.lisp 的分派表 可见,csv、fixed、dbf、ixf、sqlite、mysql、mssql、pgsql 各源类型均有对应的加载代码生成函数——这意味着你在快速入门中学会的命令行直驱模式,可以平滑延伸到这些源类型。更复杂的场景(计算列、USING 投影、BEFORE/AFTER LOAD 钩子)则可以转向 docs/ref/csv.rst、docs/ref/sqlite.rst、docs/ref/mysql.rst 等参考文档,学习完整的 pgloader 命令语法。

登录后查看全文
pgloader