我们把生产数据库从PostgreSQL 12迁移到了15,过程中踩了不少坑。

本文分享完整的迁移实战,包括迁移前准备、迁移方案、迁移步骤、验证方法、回滚方案,以及踩过的坑和经验总结。

一、为什么要迁移

1. 旧版本的问题

我们的生产数据库用的是PostgreSQL 12,已经用了三年。

遇到的问题:

  • 12版本即将停止维护
  • 一些新特性用不了(如MERGE、更好的分区表)
  • 性能不如新版本
  • 一些bug在新版本中修复了
  • 社区支持逐渐减少

2. 新版本的吸引力

PostgreSQL 15有很多吸引我们的特性:

  • MERGE语句
  • 更强大的逻辑复制
  • 性能提升
  • 更好的分区表
  • 更完善的监控
  • 安全增强

3. 迁移的目标

我们的迁移目标:

  • 从PostgreSQL 12升级到15
  • 停机时间尽量短
  • 数据不丢失
  • 性能不下降
  • 可以回滚

二、迁移前准备

迁移前的准备非常重要,准备越充分,迁移越顺利。

1. 环境准备

首先准备新环境。

  • 新服务器:配置和旧服务器相当或更好
  • 安装PostgreSQL 15
  • 配置参数(sharedbuffers、workmem等)
  • 安装必要的扩展(如pgstatstatements)
  • 网络配置,确保新旧服务器互通

2. 数据库评估

对旧数据库做全面评估。

  • 数据量:多大?
  • 表数量:多少张表?
  • 大表:哪些表特别大?
  • 索引:有多少索引?
  • 扩展:用了哪些扩展?
  • 存储过程:有多少函数和存储过程?
  • 定时任务:有哪些定时任务?
-- 查看数据库大小
SELECT pg_size_pretty(pg_database_size('mydb'));

-- 查看表大小
SELECT 
    relname,
    pg_size_pretty(pg_total_relation_size(relid)) as size
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 20;

-- 查看扩展
SELECT * FROM pg_extension;

3. 兼容性检查

检查应用和数据库的兼容性。

  • 应用用的驱动是否支持PG 15
  • ORM是否支持
  • SQL语句是否有不兼容的语法
  • 扩展是否有PG 15版本
  • 函数和存储过程是否兼容

常见的不兼容:

  • 一些废弃的函数
  • 配置参数变化
  • 系统视图变化
  • 扩展不兼容

4. 测试环境验证

在测试环境先做一次完整迁移。

  • 用生产数据的副本测试
  • 跑应用的测试用例
  • 性能测试
  • 验证所有功能
  • 记录问题和解决方案

测试环境验证通过后,再考虑生产迁移。

5. 备份

迁移前一定要备份。

# 逻辑备份
pg_dump -U postgres -Fc mydb > mydb.dump

# 物理备份(如果用PITR)
pg_basebackup -U postgres -D /backup

备份要验证可恢复,不要只备份不验证。

三、迁移方案选择

PostgreSQL迁移有几种方案,各有优缺点。

1. 方案一:pg_dump逻辑备份恢复

最简单的方案。

步骤:

  1. 旧库pg_dump导出
  2. 新库pg_restore导入
  3. 验证数据
  4. 切换应用

优点:

  • 简单,容易操作
  • 可以跨大版本
  • 可以重建索引,优化存储

缺点:

  • 停机时间长(数据量大时)
  • 导出导入期间不能写

适合:数据量不大(100GB以下),可以接受较长停机时间。

2. 方案二:pg_upgrade原地升级

用pg_upgrade工具升级。

步骤:

  1. 安装新版本
  2. 停止旧库
  3. 运行pg_upgrade
  4. 启动新库
  5. 验证

优点:

  • 速度快,不需要导出导入
  • 停机时间较短

缺点:

  • 需要在同一台机器
  • 不能跨操作系统
  • 出问题回滚困难
  • 对环境要求高

适合:同机升级,数据量大,希望停机时间短。

3. 方案三:逻辑复制

用逻辑复制做零停机迁移。

步骤:

  1. 新库创建订阅
  2. 旧库创建发布
  3. 数据同步
  4. 等追平后,切换应用
  5. 停止旧库

优点:

  • 停机时间极短(秒级)
  • 可以跨版本、跨机器
  • 可以先验证再切换

缺点:

  • 配置复杂
  • 需要旧库支持逻辑复制(PG 10+)
  • 大对象不支持
  • DDL同步有限制

适合:数据量大,要求停机时间短,有技术能力。

4. 我们的选择

我们的数据量约500GB,要求停机时间尽量短。

最终选择了逻辑复制方案:

  • 先搭建逻辑复制,同步数据
  • 等追平后,在低峰期切换
  • 停机时间只有几分钟

四、迁移步骤(逻辑复制方案)

下面是我们的详细迁移步骤。

1. 第一步:配置旧库(发布端)

在旧库(PG 12)上配置发布。

-- 修改配置,开启逻辑复制
-- postgresql.conf
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10

-- 重启数据库
-- 创建发布
CREATE PUBLICATION migration_pub FOR ALL TABLES;

-- 创建复制用户
CREATE ROLE replication_user WITH REPLICATION LOGIN PASSWORD 'password';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replication_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO replication_user;

注意:

  • wal_level要改成logical,需要重启
  • 复制用户要有足够的权限
  • FOR ALL TABLES会包含所有表,也可以指定表

2. 第二步:配置新库(订阅端)

在新库(PG 15)上配置订阅。

-- 先创建表结构(用pg_dump --schema-only)
-- 在旧库执行
pg_dump -U postgres --schema-only -Fc mydb > schema.dump
-- 在新库执行
pg_restore -U postgres -d mydb schema.dump

-- 创建订阅
CREATE SUBSCRIPTION migration_sub
    CONNECTION 'host=old-host port=5432 dbname=mydb user=replication_user password=password'
    PUBLICATION migration_pub
    WITH (copy_data = true);

注意:

  • 要先创建表结构,再创建订阅
  • copy_data = true表示先全量同步,再增量同步
  • 表结构要一致,否则同步会出错

3. 第三步:监控同步进度

创建订阅后,监控同步进度。

-- 在新库查看订阅状态
SELECT * FROM pg_stat_subscription;

-- 查看复制延迟
SELECT 
    pid,
    client_addr,
    state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    pg_wal_lsn_diff(sent_lsn, replay_lsn) as delay_bytes
FROM pg_stat_replication;

等延迟为0,表示数据追平了。

4. 第四步:同步序列

逻辑复制不会自动同步序列,需要手动同步。

-- 在旧库查看序列当前值
SELECT sequence_name, last_value FROM sequences;

-- 在新库设置序列
SELECT setval('seq_name', 10000);

可以写个脚本,批量同步所有序列。

5. 第五步:切换前准备

切换前,做好准备。

  • 通知相关人员
  • 选择低峰期(如凌晨)
  • 准备回滚方案
  • 确认数据同步完成
  • 确认序列同步完成
  • 确认无未完成的事务

6. 第六步:切换

切换的步骤:

  1. 停止应用(或切到维护模式)
  2. 等旧库没有新的写入
  3. 确认新库数据追平
  4. 修改应用配置,指向新库
  5. 启动应用
  6. 验证功能

整个切换过程,我们用了约5分钟。

7. 第七步:切换后验证

切换后,全面验证。

  • 数据一致性:对比新旧库的数据
  • 功能测试:核心功能是否正常
  • 性能测试:响应时间是否正常
  • 监控:CPU、内存、连接数
  • 错误日志:有没有报错

验证通过后,迁移完成。

五、踩过的坑

迁移过程中,我们踩了不少坑。

1. 坑一:大对象不支持逻辑复制

问题: 我们的数据库有大对象(blob),逻辑复制不支持,同步后大对象丢失了。

解决方案:

  • 用pg_dump单独导出大对象
  • 在新库导入
  • 或者把大对象改成bytea类型

经验: 迁移前检查有没有大对象,逻辑复制不支持。

2. 坑二:序列不同步

问题: 切换后,插入数据时报主键冲突。

原因: 逻辑复制不同步序列,新库的序列还是初始值。

解决方案:

  • 切换前同步所有序列
  • 写脚本批量同步
  • 切换后验证序列值

经验: 序列是逻辑复制的常见坑,一定要记得同步。

3. 坑三:扩展不兼容

问题: 旧库用了pgstatstatements扩展,新库安装后版本不兼容。

解决方案:

  • 在新库安装兼容版本的扩展
  • 升级扩展:ALTER EXTENSION pgstatstatements UPDATE
  • 或者删除后重新创建

经验: 迁移前检查所有扩展,确保新库有兼容版本。

4. 坑四:配置参数变化

问题: 新库用了旧的配置文件,启动报错。

原因: PG 15有一些配置参数废弃或改名了。

解决方案:

  • 用PG 15的默认配置文件
  • 把自定义的参数迁移过去
  • 废弃的参数去掉或改名

经验: 不要直接复制旧配置文件,要用新的默认配置,再修改。

5. 坑五:应用驱动不兼容

问题: 切换后,应用报错,连接不上数据库。

原因: 旧的JDBC驱动不支持PG 15的某些特性。

解决方案:

  • 升级应用的数据库驱动
  • 迁移前在测试环境验证
  • 确保所有应用都升级了驱动

经验: 迁移前要检查所有应用的驱动版本,提前升级。

6. 坑六:性能下降

问题: 切换后,新库性能比旧库差。

原因:

  • 新库没有统计信息,查询计划不好
  • 索引需要重建
  • 配置参数需要调优

解决方案:

  • 切换后运行ANALYZE,更新统计信息
  • 重建索引(REINDEX)
  • 根据实际情况调优参数
  • 监控慢查询,逐步优化

经验: 迁移后性能可能暂时下降,要跑ANALYZE和重建索引。

六、回滚方案

迁移要有回滚方案,万一出问题可以回退。

1. 回滚条件

什么情况下回滚:

  • 数据不一致,无法修复
  • 核心功能不可用
  • 性能严重下降,影响业务
  • 出现无法解决的bug

2. 回滚步骤

如果需要回滚:

  1. 停止应用
  2. 把应用配置改回旧库
  3. 启动应用
  4. 新库的增量数据,同步回旧库(如果有)
  5. 排查问题,准备下次迁移

3. 回滚的时间窗口

  • 切换后24小时内,可以回滚
  • 超过24小时,新库有了新数据,回滚复杂
  • 所以切换后24小时内要密切监控

七、迁移后的优化

迁移完成后,还要做一些优化。

1. 更新统计信息

ANALYZE VERBOSE;

2. 重建索引

REINDEX DATABASE mydb;

或者对大表单独重建。

3. 参数调优

根据新库的实际情况,调优参数:

  • shared_buffers
  • work_mem
  • maintenanceworkmem
  • effectivecachesize
  • checkpoint相关参数

4. 监控

迁移后加强监控:

  • 慢查询
  • 连接数
  • CPU、内存、磁盘
  • 复制状态(如果还有)
  • 设置告警

八、经验总结

这次迁移,我们总结了一些经验。

1. 充分准备

  • 迁移前的准备比迁移本身更重要
  • 测试环境一定要验证
  • 备份一定要可恢复
  • 文档要写清楚

2. 选择合适的方案

  • 根据数据量和停机要求选方案
  • 数据量小用pg_dump
  • 数据量大、停机要求高用逻辑复制
  • 不要盲目追求零停机,适合的才是最好的

3. 详细的步骤

  • 每一步都要写清楚
  • 谁执行、执行什么、预期结果
  • 回滚方案也要写清楚
  • 迁移时按步骤来,不要跳步

4. 充分测试

  • 测试环境完整测试
  • 应用兼容性测试
  • 性能测试
  • 回滚测试

5. 低峰期切换

  • 选择业务低峰期
  • 通知相关人员
  • 准备好应急
  • 切换后密切监控

九、写在最后

PostgreSQL 15迁移,是一个有风险但有价值的操作。

我们用逻辑复制方案,从12升级到15,停机时间只有5分钟,数据零丢失。虽然踩了一些坑,但最终顺利完成。

迁移的关键是:充分准备、选择合适方案、详细步骤、充分测试、低峰期切换、有回滚方案。

2022年了,PostgreSQL 15已经发布,性能和功能都有提升。如果你的数据库还是旧版本,可以考虑升级。但一定要做好准备,不要盲目操作。

最后,用一句话总结:"数据库迁移,胆大心细。充分准备,按步骤来,有回滚方案,就能顺利完成。"

愿你的数据库迁移,顺利完成,不出问题。