强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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) BIGINTINTEGER 视精度选择
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 的 TIMESTAMPTIMESTAMPTZ,而非 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
实时迁移 逻辑复制

扩展阅读