- 先给 17 做一次一致性快照
docker exec -i pg17 pg_dumpall -U postgres > /tmp/full.sql
- 停旧容器(不写 -v 不会删数据卷)
docker stop pg17
- 启动 pg18 (启用新的挂载卷)
注意 PG18 数据目录变了
docker run -d --name pg18 \
-e POSTGRES_PASSWORD=原来的密码 \
-p 5432:5432 \
-v pg18:/var/lib/postgresql/18/data \ # 复用旧卷
postgres:18.0
- 数据导入
docker exec -i pg18 psql -f dump.sql
附录
官方升级参考文档
https://www.postgresql.org/about/news/postgresql-18-released-3142/
大模型对该文章的解读
从 PostgreSQL 17 升级到 18,你有三种主流方案可选,具体取决于你对“停机时间”的容忍度、数据库大小和基础设施能力。下面按“从简到繁”逐一说明,并给出官方推荐步骤和注意事项。
✅ 方案一:pg_upgrade(最快,分钟级停机,适合单机或中小库)
核心思路:原地或并行安装 18,用 pg_upgrade 把 17 的数据文件“链”或“复制”到新集群,再切换端口/软链。
停机窗口:3–10 min(主要花在启动新实例、验证)。
前置条件
- 17 与 18 二进制并存(RPM/DEB 已提供
postgresql17/postgresql18包;Docker 可用不同 tag)。 - 两集群数据目录在同一文件系统,才能用
--link或--swap秒级迁移。 - 已安装所有旧集群用到的扩展(
.so文件版本需匹配 18)。
官方步骤(可只读校验,无需停老库)
# 1. 备份
pg_dumpall -f /safe/backup.sql # 兜底,可选
# 2. 停 17 库
systemctl stop postgresql@17-main
# 3. 初始化 18 新库(编码/locale 要与旧库一致)
/usr/pgsql-18/bin/initdb -D /var/lib/pgsql/18/data \
--encoding=UTF8 --locale=en_US.UTF-8
# 4. 兼容性预检(可在线)
/usr/pgsql-18/bin/pg_upgrade --check \
--old-datadir /var/lib/pgsql/17/data \
--new-datadir /var/lib/pgsql/18/data \
--old-bindir /usr/pgsql-17/bin \
--new-bindir /usr/pgsql-18/bin
# 5. 正式升级(--link 秒级,--jobs 并行)
/usr/pgsql-18/bin/pg_upgrade --link --jobs=$(nproc) \
--old-datadir … --new-datadir … \
--old-bindir … --new-bindir …
# 6. 切换环境
systemctl disable postgresql@17-main
systemctl enable postgresql@18-main
systemctl start postgresql@18-main
# 7. 收集统计信息 & 删除旧集群
./analyze_new_cluster.sh
./delete_old_cluster.sh
注意
- 若使用 Docker,官方镜像从 18 起把
PGDATA改成/var/lib/postgresql/18/data,需同步修改卷挂载点,否则pg_upgrade会找不到目录。 - 升级后务必
VACUUM FREEZE或autovacuum触发一次,以利用 18 新冻结策略。 - 如果旧库启用了自定义表空间,确保在相同路径存在且为空,否则
--check会失败。
✅ 方案二:pg_dumpall + restore(最稳,小时级停机,适合 <100 GB)
核心思路:逻辑全量导出 SQL,再导入新集群;零依赖、跨平台、最保险。
停机窗口:导出+导入耗时(网络/磁盘决定)。
步骤
- 停应用 → 只读事务结束。
pg_dumpall -v -f dump.sql- 起 18 新实例,
psql -f dump.sql导入。 - 验证用户/扩展/序列,重设密码、重新授权。
- 切换连接串到 18,启动应用。
优点:简单、可跨大版本、可编辑 SQL 清理垃圾。
缺点:大库慢;大对象、编码错误需手动处理。
✅ 方案三:逻辑复制(近零停机,适合 SLA 严格或大库)
核心思路:17 当主库持续对外服务,18 当逻辑从库追平后秒级切换。
停机窗口:秒级(仅切换 VIP/DNS)。
简化流程
- 17 主库:
ALTER SYSTEM SET wal_level=logical;重启。 - 创建
PUBLICATION alltables FOR ALL TABLES; - 部署 18 空库,用
pg_createsubscriber --publisher-server=... --subscription=sub1一键建成逻辑从库。 - 观察
pg_stat_subscription.replay_lsn追上主库。 - 停应用写入 → 确认无延迟 → 提升 18 为主(
pg_ctl promote)。 - 改连接串 → 启动应用 → 拆除旧 17。
注意
- 所有表须有主键或
REPLICA IDENTITY FULL。 - 大事务期间需保证 WAL 保留足够长。
- 序列不同步,切换后需手动
setval()补差。
升级后必做清单(无论哪种方案)
- 回归测试:重点验证
- 虚拟生成列、UUIDv7、新排序规则
pg_unicode_fast等 18 新特性是否影响业务。
- 虚拟生成列、UUIDv7、新排序规则
- 更新客户端驱动:JDBC 42.7+、libpq 18 建议配套,避免协议 3.2 兼容问题。
- 统计信息:立即
ANALYZE或打开auto-analyze,防止计划退化。 - 配置 diff:用
pg_upgrade生成的*.conf.sample比对,把 17 自定义参数同步到 18。 - 备份策略:确认新集群 WAL 归档、定时全量策略已生效。
- 清理:删除旧集群、旧 RPM/DEB、旧 Docker volume,避免误启动。
一句话选型
- 能停 10 分钟、单节点 →
pg_upgrade --link最快。 - <100 GB、想最稳 →
pg_dumpall逻辑导出。 - TB 级、24×7 不能停 → 逻辑复制蓝绿升级。
按上面步骤执行,即可把 PostgreSQL 17 平滑带到 18,享受 AIO、跳过扫描、并行 GIN 等性能红利。祝你升级顺利!