一条命令完成 PostgreSQL 数据迁移:pgloader 从零到一的实战指南
2026/9/6 23:24:46 网站建设 项目流程

一条命令完成 PostgreSQL 数据迁移:pgloader 从零到一的实战指南

【免费下载链接】pgloaderMigrate to PostgreSQL in a single command!项目地址: https://gitcode.com/gh_mirrors/pg/pgloader

你有没有遇到过这样的场景:公司决定从 MySQL 迁到 PostgreSQL,表结构、索引、外键、几十万行数据,全部要手工搬。你打开 psql,一条条CREATE TABLE照着抄,再用\copy导数据,结果第 371 行一条非法日期就让整个导入报废。这是很多 DBA 都经历过的噩梦。

pgloader 就是为这个场景而生的 PostgreSQL 数据加载工具。它靠一条命令就能完成从 MySQL、SQLite、SQL Server、CSV、DBF、IXF 等多种数据源到 PostgreSQL 的迁移,更关键的是——它自带智能错误隔离机制,坏数据会被挑出来单独记进日志,好数据继续入库,整个迁移不会因为一行脏数据就崩盘。本文会带你从安装开始,完整跑通一次真实迁移,再讲透配置文件、常见报错和性能调优。

第一章 为什么是它:被脏数据支配的恐惧

先说说最扎心的痛点。PostgreSQL 的COPY命令走的是事务语义:只要输入数据里有一行出错,整个表的数据全部回滚。设想你导一个 100 万行的 CSV,跑到第 80 万行遇到一个格式不对的日期,前面 80 万行全部白干。你改完错误再来一遍,又卡在下一行脏数据上。

pgloader 彻底改写了这个剧本,它的设计哲学是"有错先记下来,别挡住大部队"。底层它把数据切成 25000 行一个的批次(batch),用 COPY 协议流式灌入;一旦 PostgreSQL 拒绝某个批次,它就从错误消息里解析出问题行号,把好行重新发一遍、坏行写进独立的reject.dat文件,然后继续往后加载。

关注点传统 COPY / \copy用 pgloader 的收获
错误处理一行出错,全表回滚坏行隔离到 reject 文件,好行继续加载
数据源只认 CSV 文本MySQL/SQLite/MSSQL/CSV/DBF/IXF/归档/HTTP 全支持
库结构迁移手写 DDL,逐表抄自动发现表、索引、外键、注释、序列
数据类型手工预处理内置 CAST 规则,零日期自动转 NULL
重复执行每次都要手工清理默认 DROP+CREATE,可重复跑直到通过

别忘了它还有一个杀手锏:它可以连数据库本身一起迁。所谓 "single command" 不是只迁数据,而是 schema(表结构、索引、外键、注释)和数据一锅端。这背后是它先去源库翻目录(catalog)拿到全部结构定义,做类型映射后再开始搬数。

第二章 动手前准备:环境要求与安装清单

pgloader 目前有两个版本线,请按你的情况选。

版本说明

  • v4(推荐):基于 Clojure/JVM 的完整重写,发布为单个 JAR 文件,要求 Java 21 或更高版本。无原生依赖、无共享库,大迁移时内存溢出问题通过 JVM 堆参数(-Xmx)解决。
  • v3:Common Lisp 老版本,Debian/Ubuntu 自带apt-get install pgloader即可安装。

✅ 版本兼容提示:v4 完全兼容 v3 的.load命令文件语法和命令行参数,旧配置文件可以直接拿来用。

安装清单

方式一:下载 v4 预编译 JAR(推荐,两步搞定)

# 1. 下载 JAR(官方发布页始终指向最新构建) curl -L -o pgloader.jar https://github.com/dimitri/pgloader/releases/download/v4-dev/pgloader.jar # 2. 验证版本 java -jar pgloader.jar --version

如果你想全局使用pgloader命令,可以加一个包装脚本:

sudo install -m 755 pgloader.jar /usr/local/lib/pgloader.jar echo '#!/bin/sh\nexec java -jar /usr/local/lib/pgloader.jar "$@"' | sudo tee /usr/local/bin/pgloader sudo chmod 755 /usr/local/bin/pgloader pgloader --version

方式二:Docker 一行跑起来

docker pull ghcr.io/dimitri/pgloader:latest docker run --rm -it ghcr.io/dimitri/pgloader:latest pgloader --version

方式三:Debian/Ubuntu 用 v3 系统包

sudo apt-get install pgloader

方式四:从源码编译(所有发行版通用)

git clone https://gitcode.com/gh_mirrors/pg/pgloader cd pgloader make ./build/bin/pgloader --help # 产物在这里

动手前自查清单

  • ✅ 本地能连上目标 PostgreSQL(createdbpsql可用)
  • ✅ 源数据所在路径有读权限;从数据库迁移时源库账号有读权限
  • ⚠️ 确认目标库已创建,或确认include drop, create tables等选项生效
  • ⚠️ 大文件迁移前先看一眼磁盘剩余空间(reject 文件会占额外空间)
  • ✅ 跑任何命令前先执行pgloader --help看当前版本的参数列表

第三章 一次完整的实战:把 SQLite 库搬进 PostgreSQL

我们选 SQLite 作为第一个实战,因为它是"零前置配置"的最好示范——不需要账号密码,一个.db文件就是整个数据库。这也是 pgloader 文档里的官方入门案例。

第一步:创建目标数据库

createdb newdb

这一步在做什么:pgloader 负责建表、建索引、导数据,但"数据库本身"这个壳得先存在。就像搬家,箱子 pgloader 帮你打包,但新房子门要先开。

第二步:一条命令完成全部迁移

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

是的,就这么一行。pgloader 会依次做四件事:

  1. 打开 SQLite 文件,通过它的系统目录自动发现所有表定义
  2. 把 SQLite 的数据类型映射成 PostgreSQL 类型(CAST 规则)
  3. 在 PostgreSQL 里建表、建索引、建外键
  4. 用 COPY 协议批量灌入数据

注意目标连接串postgresql:///newdb——三个斜杠代表"本地默认端口 + 默认用户 + 数据库 newdb",这是简写,完整写法是postgresql://user:pass@localhost:5432/newdb

第三步:MySQL 迁移也一个套路

如果源是 MySQL,逻辑完全一样,只是把连接串换成 MySQL 的:

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

pgloader 会自动发现 sakila 库里的表、索引、外键、注释,全部翻译成 PostgreSQL 版本,然后并行搬数据。

第四步:看看迁移到底干了啥

想确认配置没写错、连接能通、又不真想动数据?用干跑模式:

pgloader --dry-run my-migration.load

想把过程记成日志、把结果汇成报告?加两个参数:

pgloader --verbose --logfile migration.log --summary report.txt migration.load

--summary支持.csv.json.copy后缀,机器可读,方便接进监控看板。

为什么它能自动建表?——"发现式迁移"

如果你好奇背后的原理:pgloader 迁移数据库时,会先连接源库的元数据目录,把表清单、字段类型、默认值、非空约束、主键、外键、索引、注释全部读进一个内部 catalog,再据此生成 PostgreSQL 的 DDL。所以"一条命令"不是黑魔法,而是它替你干了原本手工抄 DDL 的活。

第四章 让它更懂你:配置文件与自定义转换

命令行适合简单场景,但真实世界的数据总是脏的。当你需要指定目标表、做类型转换、迁移前建 schema、迁移后建索引时,就该上.load命令文件了。

一个足够完整的配置文件模板

LOAD DATABASE FROM mysql://root@localhost/sakila INTO postgresql://localhost:54393/sakila WITH include drop, create tables, create indexes, reset sequences, workers = 8, concurrency = 1, multiple readers per thread, rows per range = 50000 SET PostgreSQL PARAMETERS maintenance_work_mem to '128MB', work_mem to '12MB' SET MySQL PARAMETERS net_read_timeout = '120', net_write_timeout = '120' CAST type bigint when (= precision 20) to bigserial drop typemod, type date drop not null drop default using zero-dates-to-null, type year to integer ALTER SCHEMA 'sakila' RENAME TO 'pagila' BEFORE LOAD DO $$ create schema if not exists pagila; $$; AFTER LOAD DO $$ analyze pagila.*; $$;

逐段拆解:这份配置在说什么

段落作用本例含义
WITH include drop先删后建目标表存在则先 DROP,保证可重复执行
create tables, create indexes迁移结构自动建表和索引
reset sequences重置自增序列从迁移后的最大值续走
workers / concurrency并发控制8 个 worker 同时迁移多张表
SET ... PARAMETERS会话参数迁移期间调大 work_mem 加速排序
CAST ...类型转换见下文详解
BEFORE / AFTER LOAD前后钩子迁移前建 schema,迁移后收集统计信息

CAST 规则:把 MySQL 的"任性"翻译成 PostgreSQL

CAST是 pgloader 最值钱的自定义能力。举个经典例子:MySQL 的日历里存在公元 0 年0000-00-00),而 PostgreSQL 直接拒绝这种非法日期。pgloader 内置了一条规则把这些零日期自动转成NULL

CAST type date drop not null drop default using zero-dates-to-null

再看几个常用写法:

-- 把 MySQL 的 unsigned bigint(20) 翻译成自增 bigserial CAST type bigint when (= precision 20) to bigserial drop typemod, -- tinyint 不转布尔(默认会转),改成整数 -- type tinyint to boolean using tinyint-to-boolean, -- 注释掉即可停用 CAST type year to integer,

你还可以针对具体列下规则,比如把base64.data列解码成jsonb、把身份证列统一转成uuid。规则粒度从"某种类型"到"某个表的某列"都支持,够灵活。

第五章 避坑锦囊:高频报错一次说清

迁移踩坑是必经之路,这里把我见过的高频问题按"症状 → 根因 → 解法"整理给你。

坑 1:一到某行就报错,整个导入失败

  • 症状:加载 CSV 中途报COPY errors, line 3, column b: "2006-13-11",然后全部回滚。
  • 根因:文件类数据源默认on error resume next是开启的,理论上不会全挂;你会遇到全挂,多半是手滑开了on error stop
  • 解法:确认WITH on error resume next(文件源默认值)。数据库源迁移默认是on error stop,因为重跑迁移更安全,但如果你想"坏了就跳过",显式加WITH on error resume next

坑 2:提示 Java 版本不对,JAR 跑不起来

  • 症状java -jar pgloader.jarUnsupportedClassVersionError或类似错误。
  • 根因:pgloader v4 强制要求Java 21+,你的机器装的是老 JDK。
  • 解法:先java -version确认版本,升级到 Temurin 或 OpenJDK 21。装好后再java -jar pgloader.jar --version验证。

坑 3:MySQL 连不上,报 SSL 或认证错误

  • 症状mysql://root:pass@db:3306/mydb连接失败。
  • 根因:新版 MySQL(尤其 8.x)默认走 SSL 或要求 RSA 公钥交换,常见于本地 Docker 环境。
  • 解法:连接串加参数显式关掉 SSL。v4 支持原生 URI 和标准 JDBC URL 两种写法:
pgloader 'mysql://root:pass@db:3306/mydb?useSSL=false' postgresql:///target pgloader 'jdbc:mysql://root:pass@db:3306/mydb?useSSL=false' postgresql:///target

坑 4:导出乱码,中文全变问号

  • 症状:迁移后中文显示乱码。
  • 根因:源数据的实际编码和库表元数据里声明的不一致(MySQL 常见),或目标连接默认字符集不对。
  • 解法:用DECODING TABLE NAMES MATCHING覆盖声明,或迁移前在SET里固定 client_encoding:
SET client_encoding to 'latin1'

坑 5:迁移被中断,不知道死在哪

  • 症状:跑到一半报错退出,找不到问题行。
  • 根因:不想让坏行干扰排查。
  • 解法:排查阶段用--on-error-stop,让它在第一条被拒数据处停下,配合--logfile看完整上下文;修好之后再切回默认继续模式跑全量。

第六章 性能与效率心得:把大迁移跑出高水位

pgloader 底层是"读线程 → 队列 → 写线程 → COPY"的流水线模型,性能参数基本就是围绕这条流水线设置的。下面这些数字都是真实参数,可以照抄再按你的机器微调。

1. 批量参数:别让单批次过小

批处理机制默认 25000 行一个批次。批次越小,出错重试越精细,但吞吐也越低。文件干净的情况下可以调大:

WITH batch rows = 50000, batch size = 100MB, prefetch rows = 100000

2. 并发参数:worker 不是越多越好

workers控制同时搬几张表:数据库源默认 4,文件源默认 8。concurrency控制单表内并行度(需大于 1,且源要支持按主键范围或 ctid 范围分片)。

WITH workers = 8, concurrency = 4, chunk size = 50MB

注意:concurrency = 4意味着这张表同时跑 4 条独立的读→写流水线,各读各的分片,写是配对的。机器核数不够时别硬堆。

3. 索引策略:数据先进来,索引后建

迁移期间建索引很拖速度。合理做法是:

WITH create indexes, max parallel create index = 2

或者干脆数据先导进来,用AFTER LOAD DO再建索引:

AFTER LOAD DO $$ create index idx_orders_created_at on orders (created_at); $$;

4. 目标库参数:迁移时临时调大内存

排序、建索引都吃内存,迁移窗口内调大不影响平时:

SET maintenance_work_mem to '512MB', work_mem to '32MB'

5. 关于极限速度的实话

文档里写得很实在:如果数据源本身是 COPY 能直接读的干净文件,pgloader 不会比原生 COPY 更快。它卖的不是极限速度,而是"脏数据也能扛 + 复杂转换也能做 + 全程一条命令"。想快,就保证源数据干净;想稳,就放心交给它。

第七章 从这里继续进阶:源码、文档与示例

项目源码和文档都在仓库里,按下面的索引去读,效率最高。

  • 官方文档:docs/index.rst 是总入口,含全部手册;docs/quickstart.rst 讲最快上手路径
  • 命令语法手册:docs/command.rst,.load命令 DSL 的完整文法;批处理与并行机制看 docs/batches.rst
  • 各数据源手册:docs/ref/mysql.rst、docs/ref/sqlite.rst、docs/ref/mssql.rst、docs/ref/csv.rst
  • 核心加载逻辑源码:src/load/ 是入口,src/pgsql/ 是 PostgreSQL 端实现
  • 转换函数源码:src/utils/transforms.lisp,想自定义数据清洗可以照这里的写法扩展
  • 真实可用示例:test/ 目录里全是官方.load文件,test/mysql/my.load 是 MySQL 迁移的完整范例,test/csv.load 是 CSV 场景带注释的范本
  • 测试数据:test/data/ 里有可以直接练手的 DBF、CSV 文件

结语:好的工具让迁移从项目变成例行公事

回到开头的那个噩梦:手工抄 DDL、逐行排错、一次失败全盘重来。有了 pgloader,这些都变成了它替你扛的细节。它不完美——极限吞吐比不上裸 COPY,遇到实在无解的数据还是要回到--on-error-stop逐条修——但它把"数据迁移"从一件让人头皮发麻的大工程,压缩成了一条可以写进 CI、每天夜里自动跑一遍的命令。文档里把那套做法叫Continuous Migration:天天迁、次次验证,直到全绿,然后择日切库,毫无惊吓。

给你的下一步行动建议很具体:今晚就createdb newdb,拿仓库里test/data/的一个 CSV 或 DBF 文件跑一次pgloader,五分钟内你就能亲眼看到"一条命令搬完一张表"到底是什么感觉。等你能把那张表跑通,再翻开 docs/command.rst 写你的第一个.load文件。工具不怕用不熟,就怕你还没开始。

【免费下载链接】pgloaderMigrate to PostgreSQL in a single command!项目地址: https://gitcode.com/gh_mirrors/pg/pgloader

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询