PostgreSQL数据库迁移实践:场景分类、方案对比与数据校验指南

举报
数据库小学妹 发表于 2026/08/04 15:58:51 2026/08/04
【摘要】 PostgreSQL迁移的完整实操指南:覆盖跨服务器迁移、上云迁移、版本升级、跨云迁移、异构迁移五种核心场景,对比pg_dump、pg_basebackup、逻辑复制、专业迁移工具四套方案的适用边界,附迁移后数据一致性校验方法与避坑清单。

大家好,我是数据库小学妹 👋

上周有个朋友找我帮忙。他们公司要把跑了三年的PostgreSQL数据库从本地机房迁到云上,200G数据,业务不能停。他先用了pg_dump导出,跑了一晚上没跑完,第二天业务直接卡死。后来改方案又踩了角色权限的坑,序列值对不上,前后折腾了快两周。

他问我,PostgreSQL迁移到底应该按什么思路来?

我想了很久。因为PostgreSQL迁移不是一个动作,而是一套决策。什么场景、选什么方案、用什么工具、迁移完怎么验证。每个环节都有坑,每一步都不能省。

PostgreSQL迁移,指的是将PostgreSQL数据库从一个运行环境完整转移到另一个环境的过程,包括结构迁移、数据迁移、权限迁移和迁移后验证四个阶段。迁移方式可以按数据量、停机窗口和目标环境分为多种方案。

今天把常见的迁移场景梳理一遍。从最简单的跨服务器搬数据,到不停机迁移,再到异构数据库替换。每个场景对应什么方案、踩什么坑、怎么验证,都写清楚。


PostgreSQL迁移前检查清单

动手之前,先过一遍清单。这些是迁移时最容易忽略的前置动作。

确认版本兼容。大版本不同(比如11到15),pg_dump导出的SQL可能包含目标库不支持的语法。先在目标库跑一遍\l确认版本,小版本差异一般没问题。

评估数据量和停机窗口。200G以上的库,单线程pg_dump导出可能要跑大半天。数据量直接决定能不能用pg_dump方案,停机窗口决定业务能接受多长的中断时间。

检查网络连通性。源库到目标库之间的延迟直接影响迁移速度。云环境下提前配置好安全组、VPC和防火墙规则,别等导出跑完了才发现目标库连不上。

提前做好全量备份。不管选哪种方案,迁移前先用pg_dump做一份完整备份放到独立存储。我有一次做迁移,源库数据直接搞坏了,幸亏提前留了备份。

列好extension清单。PostGIS、pgcrypto、uuid-ossp这些扩展插件不会自动迁移。迁移前在源库跑一遍\dx,把结果截个图或记下来,目标库初始化时就装上,免得导入时报"extension does not exist"。如果是迁移到金仓KES这类国产数据库,兼容性评估阶段就要把extension的替代方案一起确认,KES对大部分常用扩展都有对应的兼容实现。


一、PostgreSQL迁移的五种场景

很多人一上来就选工具,这个顺序其实搞反了。要先搞清楚你要解决的是哪种迁移场景,这样工具选型自然就出来了。

1.1 跨服务器迁移

最常见的场景。旧服务器退役,数据搬到新机器。或者开发环境的数据同步到测试环境。

同源同版本,目标端是全新的PostgreSQL实例。数据量从几GB到几百GB都有。

1.2 上云迁移

本地PostgreSQL迁到云数据库,比如阿里云RDS、腾讯云TDSQL。

目标端是托管服务,没有superuser权限。角色权限模型和自建库不同,这是和跨服务器迁移最大的区别。

1.3 版本升级

从PostgreSQL 11升到15,或者从14升到17。

同服务器、同实例,只是版本变了。但大版本升级涉及系统目录结构变化,不能简单复制data目录。

1.4 跨云迁移

从一个云厂商迁到另一个。比如阿里云RDS迁到腾讯云,或者AWS RDS迁回本地。

两端都是托管环境,网络延迟大,且双方权限都受限。

1.5 异构迁移

从PostgreSQL迁到另一个数据库引擎。比如信创场景下迁到国产数据库。

SQL语法、数据类型、存储过程语言可能完全不同。异构迁移最难的部分不是数据搬运,而是兼容性评估和语法改造。


二、主流PostgreSQL迁移方案对比

场景明确了,再看方案。我把主流方案归为四类:

方案 适用场景 停机时间 数据量上限 复杂度
pg_dump + pg_restore 跨服务器、小数据量上云 高(数小时) <100GB
物理复制(pg_basebackup) 大版本内迁移、灾备 中(分钟级) 无上限
逻辑复制(Logical Replication) 不停机迁移、跨云 极低(秒级切换) 无上限
专业迁移工具(KDTS等) 异构迁移、大规模上云 可做到不停机 无上限
pg_upgrade 同机大版本升级 低(分钟级) 无上限

下面逐个拆解。

2.1 pg_dump + pg_restore:常用,也常踩坑

绝大多数人的第一选择。pg_dump是PostgreSQL自带的,不用装额外工具。

标准操作流程:

源端导出:

pg_dump -h 源库IP -p 5432 -U postgres -d mydb -F c -f /tmp/mydb.dump

目标端导入:

pg_restore -h 目标库IP -p 5432 -U postgres -d mydb -c /tmp/mydb.dump

-F c表示custom格式,pg_restore能读取。-c会在导入前先drop已有对象,避免冲突。

但有几个坑比较常见:

pg_dump不导出全局对象。角色、用户、表空间这些是全局的,需要额外用pg_dumpall -g导出。

上云场景没有superuser。阿里云RDS、腾讯云TDSQL这些托管服务,master用户不是superuser。很多在自建库能正常执行的pg_dump命令,到云上就报权限错误。这时候需要修改导出的SQL,把OWNER TO postgres改成OWNER TO master用户。

大数据量导出慢。pg_dump是单线程的,100GB以上的库可能跑好几个小时。可以用-j参数做并行导出,但-j--single-transaction不能同时用。

2.2 pg_basebackup:物理级复制,适合大数据量

数据量超过几百GB时,pg_dump不太合适了。

pg_basebackup做的是物理级别的备份,直接把PostgreSQL的data目录完整复制过来。速度快,但要求源和目标大版本一致。

pg_basebackup -h 源库IP -D /var/lib/pgsql/data -U replicator -P -v -R

-R会自动生成standby.signal和连接配置,方便后续启动为standby或promote为主库。

适用于同大版本的PostgreSQL迁移,数据量大,能接受分钟级停机窗口的场景。

迁移前要停写,确保数据一致。迁移后需要修改postgresql.conf和pg_hba.conf中的IP配置,否则启动会失败。

2.3 逻辑复制:不停机PostgreSQL迁移的手段

业务24小时不能停的话,逻辑复制是目前比较成熟的方案。

原理是在源库配置发布(publication),目标库配置订阅(subscription)。全量数据先同步一遍,之后源库的增量变更通过WAL日志实时推到目标库。两边数据保持同步,业务可以在任意时间窗口做最终切换。

源库配置发布:

CREATE PUBLICATION my_migration_pub FOR ALL TABLES;

目标库配置订阅:

CREATE SUBSCRIPTION my_migration_sub
  CONNECTION 'host=源库IP dbname=mydb user=replicator password=xxx'
  PUBLICATION my_migration_pub;

切换时只需要在目标库停掉订阅,把应用连接指向新库,整个过程通常几秒钟。

逻辑复制有几个前提条件:

  • 源库需要设置wal_level = logical
  • 每张需要复制的表必须有主键或REPLICA IDENTITY
  • 序列值不会自动同步,切换前需要手动修正
  • DDL变更(ALTER TABLE等)不会自动复制

2.4 专业迁移工具:异构场景和大规模上云

PostgreSQL迁移涉及异构数据库时,比如迁到国产数据库金仓KES,纯手工方式效率太低。专业迁移工具更靠谱。

以金仓数据迁移工具 Kingbase Data Migration Tool(KDTS)为例,流程大致是:

  1. 兼容性评估:用KDMS扫描源PostgreSQL库,自动生成兼容性报告,标记哪些对象可以直接迁移、哪些需要改造
  2. 结构迁移:自动转换表结构、索引、约束、序列等DDL,处理数据类型映射
  3. 全量迁移:并行导出数据并导入目标库,支持断点续传
  4. 增量同步:基于日志捕获变更数据,实时同步到目标端

异构迁移最耗时的是存储过程改造。PL/pgSQL到PL/SQL的语法差异比较大,函数签名、异常处理、游标写法都要调整。KDMS的评估报告会把这些问题标出来,能自动修的直接修,修不了的再交给DBA手工改。

某制造企业源库有数百张表和大量存储过程。KDMS评估后多数兼容性问题可以自动修复,剩下主要是PL/pgSQL特有语法和少量数组类型映射,人工改造几周就搞定了。

2.5 pg_upgrade:同机大版本升级的快捷方式

版本升级场景下(比如PostgreSQL 11升到15),如果新旧版本装在同一台机器上,pg_upgrade是比较高效的方案。

它直接读取旧版本的数据目录,在新版本的数据目录中重建系统目录,不需要导出再导入SQL。速度比pg_dump快很多,因为数据文件本身不移动,只是系统目录结构被更新。

两种模式:

--link模式:用硬链接代替复制,几乎不需要额外磁盘空间,速度极快。但升级完成后旧版本就不能再启动了,因为数据文件已经被新版本链接走。

--copy模式:完整复制数据文件,需要双倍的磁盘空间,但升级完成后旧版本仍然可用,出问题可以回退。

pg_upgrade -b /usr/lib/postgresql/11/bin -B /usr/lib/postgresql/15/bin \
  -d /var/lib/postgresql/11/main -D /var/lib/postgresql/15/main \
  --link --check

--check参数只做预检查不实际升级,建议先跑一遍check确认没有兼容性问题再执行。

pg_upgrade完成后还需要运行analyze_new_cluster.sh脚本更新统计信息,否则查询计划器会使用过时的统计数据,查询性能可能暂时下降。


三、PostgreSQL迁移后的数据一致性校验

这一步,绝大多数教程都不写。我吃过亏,所以必须写。迁移完成不等于迁移成功。数据有没有丢?序列值对不对?索引有没有漏建?都需要验证。

3.1 对象级校验

对比源库和目标库的数据库对象数量:

-- 对比表数量
SELECT count(*) FROM information_schema.tables 
WHERE table_schema = 'public' AND table_type = 'BASE TABLE';

-- 对比索引数量
SELECT count(*) FROM pg_indexes WHERE schemaname = 'public';

-- 对比序列值
SELECT last_value FROM my_sequence;

序列值容易忽略。PostgreSQL迁移后,序列值可能停在旧位置。业务继续写入就会报主键冲突。切换前一定要检查所有序列,确保last_value不小于源库。

3.2 数据级校验

抽样核对核心表的数据量:

SELECT tablename, n_live_tup 
FROM pg_stat_user_tables 
ORDER BY n_live_tup DESC;

关键业务表做行数对比和内容抽查。条件允许的话,用数据对比工具逐行校验。金仓KDC提供了结构对比和数据对比能力,能自动识别差异对象并生成订正SQL。

3.3 功能级校验

跑一遍核心业务的回归测试。用户登录、订单创建、报表查询,这些高频操作在目标库上能不能正常跑通,是最终的验证标准。


四、PostgreSQL迁移决策框架

面对一个具体的PostgreSQL迁移任务,按这个流程走:

步骤 判断维度 决策点 推荐方案 注意事项
第一步:明确场景 迁移场景 同版本跨服务器 pg_dump/pg_restore 数据量<100GB够用
上云托管 pg_dump+角色预创建 目标端无superuser,需改OWNER
大版本升级 pg_upgrade或逻辑复制 不可直接复制data目录
跨云迁移 逻辑复制或专业工具 两端都受限,网络延迟大
异构迁移 先做兼容性评估 SQL语法/数据类型需改造
第二步:看数据量 数据量级 <100GB pg_dump 单线程,预估导出时间
100GB~1TB pg_dump并行或pg_basebackup -j--single-transaction互斥
>1TB 物理复制或逻辑复制 需提前规划停机窗口
第三步:看停机窗口 可接受停机时间 能接受数小时 pg_dump/pg_restore 最简单,但停机时间最长
分钟级 pg_basebackup或逻辑复制 切换前需同步序列值
要求不停机 逻辑复制或专业工具 需配置WAL和publication
第四步:迁移后验证 验证方式 对象对比 表/索引/序列数量对比 用information_schema和pg_indexes
数据校验 核心表行数对比 条件允许做逐行校验
业务回归 高频操作跑一遍 登录/订单创建/报表查询

五、PostgreSQL迁移常见错误与排查

这一步很多讲PostgreSQL迁移的文章都会讲。我把反复遇到的报错整理出来,附排查命令和修复方法。

5.1 权限报错:permission denied for extension

上云迁移最常见。源库有superuser,目标云数据库(阿里云RDS、腾讯云TDSQL、AWS RDS)的master用户不是superuser。pg_dump导出的SQL里包含CREATE EXTENSION plpgsql之类的语句,到云上执行直接报错。

修复方法:打开导出的SQL文件,找到CREATE EXTENSION相关语句,确认目标库是否已预装该扩展。用\dx查看目标库已安装的扩展列表。plpgsql在云数据库通常已预装,直接删掉这条语句即可。

-- 查看目标库已安装的扩展
\dx

5.2 角色不存在:role “postgres” does not exist

pg_dump不导出全局角色,但导出的SQL里包含OWNER TO postgres这样的语句。导入目标库时如果postgres用户不存在,每条ALTER TABLE都会报错。

修复方法有两种。第一种是迁移前用pg_dumpall -g单独导出全局角色,先在目标库创建好用户再导入数据。第二种是批量替换SQL文件中的OWNER语句:

# 把OWNER TO postgres替换为目标库的master用户
sed -i 's/OWNER TO postgres/OWNER TO master_user/g' dump.sql

云环境下还要注意,某些角色属性(SUPERUSER、BYPASSRLS)在目标库不被允许。从role.sql中去掉这些属性再执行。如果是迁到金仓KES这类对PostgreSQL生态兼容度较高的数据库,角色和权限模型基本保持一致,pg_dump导出的SQL可以直接使用,不需要做OWNER替换,这比迁到云托管服务要省事不少。

5.3 序列值不同步:主键冲突

逻辑复制不复制序列值,pg_dump用默认参数导出时,序列值可能不是最新的。迁移完成后业务继续写入,新插入数据的id和已有数据冲突。

排查方法:在源库和目标库分别执行:

-- 查看序列当前值
SELECT last_value FROM my_table_id_seq;

-- 对比源库和目标库的结果,取较大值修正
SELECT setval('my_table_id_seq', 源库last_value);

如果表比较多,可以用这条SQL一次性查出所有序列的当前值:

SELECT c.relname AS sequence_name, last_value
FROM pg_sequences s
JOIN pg_class c ON c.relname = s.sequencename;

5.4 pg_restore导入中断后无法继续

用了-j并行参数就不能加--single-transaction,一旦中途报错,已导入的部分不会回滚。这时候直接重新跑会报"关系已存在"。

修复方法:清空目标库后重新导入,或者用pg_restore --list查看TOC列表,跳过已导入的部分继续。建议导入前先用\l确认目标库是干净的,或者用-c参数在导入前先drop已有对象。


六、PostgreSQL迁移避坑清单

反复踩的坑,总结成几条。具体报错排查见上一节,这里只写注意事项。

全量备份一定放在独立存储。我有一次备份文件和源库放在同一台机器上,迁移过程中磁盘故障,备份跟着一起丢了。备份要放到另一台机器或对象存储上。

pg_basebackup迁移前必须停写。物理复制要求数据一致,迁移开始前先停掉应用的写操作,确认没有活跃事务再执行,否则复制过来的data目录启动后可能出现数据不一致。

pg_upgrade升级后别急着上线。升级完成后要跑analyze_new_cluster.sh更新统计信息,不然查询计划器会用旧统计数据,慢查询会突然变多。等analyze跑完、核心业务测试通过了再切换流量。

异构迁移先跑兼容性评估再动手。不要一上来就导数据。用工具扫一遍源库,看清楚哪些能自动迁移、哪些要手工改,心里有数再执行,能省大量返工时间。


小结

PostgreSQL迁移不是一个工具能解决的。场景不同、方案不同、坑也不同。跨服务器小数据量用pg_dump比较省心,大数据量上物理复制或逻辑复制,同机版本升级用pg_upgrade效率高,异构迁移先做评估再动手。迁移完一定要做验证,对象对比、数据校验、业务回归,三步缺一不可。如果是信创场景下的异构迁移,金仓KES对PostgreSQL的兼容度高,迁移工具和兼容性评估也比较成熟,能减少不少改造工作量。

大家在做PostgreSQL迁移时遇到过什么坑?或者有什么好的迁移经验?评论区聊聊 👇


我是数据库小学妹,咱们下篇见 👋

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。