强曰为道

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

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)BOOLEANora2pg 自动转换
NUMBER(n)NUMERIC(n)
NUMBER(n,0)BIGINTINTEGER视精度选择
VARCHAR2(n)VARCHAR(n)TEXT建议用 TEXT
CLOBTEXT
BLOBBYTEA
DATETIMESTAMPTZOracle DATE 包含时间
TIMESTAMP WITH LOCAL TIME ZONETIMESTAMPTZ
ROWIDctid 或自增主键需要改造
SEQUENCE.NEXTVALnextval('seq') 或 IDENTITY

⚠️ 注意事项:Oracle 的 DATE 类型包含时间部分,对应 PostgreSQL 的 TIMESTAMPTIMESTAMPTZ,而非 DATE。这是最常见的迁移陷阱。


19.3 其他迁移工具

工具来源目标特点
pgloaderMySQL/MS SQL/SQLite/CSVPG最通用
ora2pgOraclePGOracle 专用,最成熟
pg_chameleonMySQLPG实时复制
AWS DMS多种PG(RDS/Aurora)云环境
pg_dump/pg_restorePGPG同版本迁移

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)BOOLEANpgloader 自动转换
INT / BIGINTINTEGER / BIGINT
DOUBLEDOUBLE PRECISION
VARCHAR(n)VARCHAR(n)TEXT建议 TEXT
TEXT / MEDIUMTEXT / LONGTEXTTEXT
DATETIMETIMESTAMPTZ注意时区
TIMESTAMPTIMESTAMPTZPG 的 TIMESTAMP 不含时区
ENUM('a','b')TEXT + CHECK 或自定义 ENUMPG 的 ENUM 修改不如 MySQL 灵活
JSONJSONBPG 的 JSONB 更强大
BLOB / LONGBLOBBYTEA
AUTO_INCREMENTGENERATED ALWAYS AS IDENTITY

19.6 迁移检查清单

步骤说明
☐ 数据库 schema 对比类型映射、约束差异
☐ 索引迁移确保索引被正确创建
☐ 数据一致性验证行数对比、校验和
☐ 性能基准测试迁移后执行 EXPLAIN ANALYZE
☐ 应用兼容性测试SQL 语法差异、驱动兼容
☐ 回退方案确保能回退到旧系统
☐ 监控告警迁移后密切关注性能指标

业务场景

场景推荐方案
PG 版本升级pg_upgrade
MySQL → PGpgloader
Oracle → PGora2pg
小量数据 (< 1GB)pg_dump/pg_restore
实时迁移逻辑复制

扩展阅读