PostgreSQL 完全指南 / 19 - 数据迁移
第 19 章 · 数据迁移
本章介绍 PostgreSQL 版本升级、从其他数据库迁移到 PG 以及常用迁移工具。
19.1 版本升级
升级方式对比
| 方式 |
停机时间 |
适用场景 |
风险 |
| pg_upgrade |
分钟级 |
大版本升级(推荐) |
低 |
| 逻辑复制 |
秒级 |
跨版本热迁移 |
中 |
| pg_dump/pg_restore |
小时级 |
小数据库 |
低 |
| pg_upgrade –link |
分钟级 |
超大数据库 |
中 |
pg_upgrade
# 1. 安装新版本
sudo apt install postgresql-17
# 2. 停止所有 PostgreSQL 服务
sudo systemctl stop postgresql
# 3. 检查兼容性
/usr/lib/postgresql/17/bin/pg_upgrade \
--old-datadir=/var/lib/postgresql/16/main \
--new-datadir=/var/lib/postgresql/17/main \
--old-bindir=/usr/lib/postgresql/16/bin \
--new-bindir=/usr/lib/postgresql/17/bin \
--check
# 4. 执行升级
/usr/lib/postgresql/17/bin/pg_upgrade \
--old-datadir=/var/lib/postgresql/16/main \
--new-datadir=/var/lib/postgresql/17/main \
--old-bindir=/usr/lib/postgresql/16/bin \
--new-bindir=/usr/lib/postgresql/17/bin \
--link # 使用硬链接,速度极快(但两版本共享数据目录)
# 5. 更新统计信息
analyze_new_cluster.sh
# 6. 启动新版本
sudo systemctl start postgresql-17
⚠️ 注意事项:使用 --link 时,旧版本数据目录会被链接到新目录,删除旧版本会破坏数据。必须先做完整备份!
19.2 pgloader(Oracle → PostgreSQL)
pgloader 是最流行的异构数据库迁移工具。
安装
sudo apt install pgloader
# 或 Docker
docker pull dimitri/pgloader:latest
MySQL → PostgreSQL
# 命令行
pgloader mysql://user:pass@mysql-host/mydb postgresql://user:pass@pg-host/mydb
# 配置文件(mysql.load)
LOAD DATABASE
FROM mysql://user:pass@mysql-host/mydb
INTO postgresql://user:pass@pg-host/mydb
WITH include drop, create tables, create indexes,
reset sequences, downcase identifiers
SET PostgreSQL PARAMETERS
maintenance_work_mem to '512MB'
CAST type datetime to timestamptz drop default drop not null using zero-dates-to-null,
type year to integer drop typemod
EXCLUDE TABLE NAMES LIKE 'temp_%', 'log_%'
BEFORE LOAD DO
$$ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; $$
AFTER LOAD DO
$$ ANALYZE; $$;
Oracle → PostgreSQL (pgloader)
# pgloader 也支持 Oracle(需要 Oracle Instant Client)
pgloader oracle://user:pass@oracle-host:1521/ORCL \
postgresql://user:pass@pg-host/mydb
19.2.1 ora2pg(Oracle 专用迁移工具)
ora2pg 是 Oracle 到 PostgreSQL 最专业的迁移工具,支持 Schema 转换、数据迁移和代码翻译。
# 安装
sudo apt install ora2pg
# 初始化配置模板
ora2pg --project_base /opt/migration --init_project myproject
# 编辑配置 /opt/migration/myproject/ora2pg.conf
# ORACLE_DSN dbi:Oracle:host=oracle-host;sid=ORCL;port=1521
# ORACLE_USER system
# ORACLE_PWD manager
# PG_DSN dbi:Pg:dbname=mydb;host=pg-host;port=5432
# PG_USER postgres
# PG_PWD password
# 只迁移 Schema
ora2pg -c ora2pg.conf --type TABLE --dump_schema > schema.sql
# 迁移数据
ora2pg -c ora2pg.conf --type COPY --dump_data > data.sql
# 迁移 PL/SQL → PL/pgSQL
ora2pg -c ora2pg.conf --type FUNCTION --dump_as_html > functions.html
# 生成迁移报告
ora2pg -c ora2pg.conf --estimate_cost
Oracle → PG 类型映射
| Oracle 类型 |
PostgreSQL 类型 |
说明 |
NUMBER(1) |
BOOLEAN |
ora2pg 自动转换 |
NUMBER(n) |
NUMERIC(n) |
— |
NUMBER(n,0) |
BIGINT 或 INTEGER |
视精度选择 |
VARCHAR2(n) |
VARCHAR(n) 或 TEXT |
建议用 TEXT |
CLOB |
TEXT |
— |
BLOB |
BYTEA |
— |
DATE |
TIMESTAMPTZ |
Oracle DATE 包含时间 |
TIMESTAMP WITH LOCAL TIME ZONE |
TIMESTAMPTZ |
— |
ROWID |
ctid 或自增主键 |
需要改造 |
SEQUENCE.NEXTVAL |
nextval('seq') 或 IDENTITY |
— |
⚠️ 注意事项:Oracle 的 DATE 类型包含时间部分,对应 PostgreSQL 的 TIMESTAMP 或 TIMESTAMPTZ,而非 DATE。这是最常见的迁移陷阱。
19.3 其他迁移工具
| 工具 |
来源 |
目标 |
特点 |
| pgloader |
MySQL/MS SQL/SQLite/CSV |
PG |
最通用 |
| ora2pg |
Oracle |
PG |
Oracle 专用,最成熟 |
| pg_chameleon |
MySQL |
PG |
实时复制 |
| AWS DMS |
多种 |
PG(RDS/Aurora) |
云环境 |
| pg_dump/pg_restore |
PG |
PG |
同版本迁移 |
19.4 CSV 批量导入
-- COPY 命令(最快)
COPY employees (name, email, age, salary)
FROM '/tmp/employees.csv'
WITH (FORMAT csv, HEADER true, DELIMITER ',', NULL '');
-- 从 STDIN(编程方式)
\COPY employees (name, email) FROM STDIN WITH CSV HEADER
-- 使用 fdw 导入
CREATE FOREIGN TABLE csv_import (
name TEXT, email TEXT
) SERVER csv_server
OPTIONS (filename '/tmp/data.csv', format 'csv', header 'true');
INSERT INTO employees (name, email)
SELECT name, email FROM csv_import;
批量导出
-- 导出为 CSV
COPY (SELECT * FROM employees WHERE department = '工程部')
TO '/tmp/engineering.csv' WITH (FORMAT csv, HEADER true);
-- \COPY(客户端导出)
\COPY employees TO '/tmp/employees.csv' WITH CSV HEADER
19.5 数据一致性验证
-- 行数对比(源库和目标库分别执行)
SELECT table_name, row_count
FROM (
SELECT 'employees' AS table_name, count(*) AS row_count FROM employees
UNION ALL
SELECT 'orders', count(*) FROM orders
UNION ALL
SELECT 'products', count(*) FROM products
) sub
ORDER BY table_name;
-- 校验和验证(对比特定列)
SELECT
count(*) AS total_rows,\ sum(hashtext(row::text)) AS checksum
FROM employees;
-- 使用 pg_comparator 扩展进行跨库对比
-- 或手动编写脚本:
-- 1. 源库 count(*) 导出
-- 2. 目标库 count(*) 对比
-- 3. 抽样对比关键字段
MySQL → PG 类型映射
| MySQL 类型 |
PostgreSQL 类型 |
注意事项 |
TINYINT(1) |
BOOLEAN |
pgloader 自动转换 |
INT / BIGINT |
INTEGER / BIGINT |
— |
DOUBLE |
DOUBLE PRECISION |
— |
VARCHAR(n) |
VARCHAR(n) 或 TEXT |
建议 TEXT |
TEXT / MEDIUMTEXT / LONGTEXT |
TEXT |
— |
DATETIME |
TIMESTAMPTZ |
注意时区 |
TIMESTAMP |
TIMESTAMPTZ |
PG 的 TIMESTAMP 不含时区 |
ENUM('a','b') |
TEXT + CHECK 或自定义 ENUM |
PG 的 ENUM 修改不如 MySQL 灵活 |
JSON |
JSONB |
PG 的 JSONB 更强大 |
BLOB / LONGBLOB |
BYTEA |
— |
AUTO_INCREMENT |
GENERATED ALWAYS AS IDENTITY |
— |
19.6 迁移检查清单
| 步骤 |
说明 |
| ☐ 数据库 schema 对比 |
类型映射、约束差异 |
| ☐ 索引迁移 |
确保索引被正确创建 |
| ☐ 数据一致性验证 |
行数对比、校验和 |
| ☐ 性能基准测试 |
迁移后执行 EXPLAIN ANALYZE |
| ☐ 应用兼容性测试 |
SQL 语法差异、驱动兼容 |
| ☐ 回退方案 |
确保能回退到旧系统 |
| ☐ 监控告警 |
迁移后密切关注性能指标 |
业务场景
| 场景 |
推荐方案 |
| PG 版本升级 |
pg_upgrade |
| MySQL → PG |
pgloader |
| Oracle → PG |
ora2pg |
| 小量数据 (< 1GB) |
pg_dump/pg_restore |
| 实时迁移 |
逻辑复制 |
扩展阅读