2025年9月25日: PostgreSQL 18 发布!
支持的版本:当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0

pg_upgrade

pg_upgrade — 升级 PostgreSQL 服务器实例

概要

pg_upgrade -b oldbindir [-B newbindir] -d oldconfigdir -D newconfigdir [option...]

描述

pg_upgrade (以前称为 pg_migrator) 允许在不进行通常需要进行主版本升级的转储/恢复操作(例如,从 12.14 升级到 13.10 或从 14.9 升级到 15.5)的情况下,将 PostgreSQL 数据文件中的数据升级到更高版本。对于次要版本升级(例如,从 12.7 升级到 12.8 或从 14.1 升级到 14.5),则不需要此工具。

PostgreSQL 的主要发布版本定期会添加新功能,这些功能经常会改变系统表的布局,但内部数据存储格式很少改变。pg_upgrade 利用这一事实,通过创建新的系统表并简单地重用旧的用户数据文件来执行快速升级。如果未来的主版本更改了数据存储格式,导致旧数据格式不可读,那么 pg_upgrade 将无法用于此类升级。(社区将尽力避免这种情况。)

pg_upgrade 会尽力确保旧集群和新集群在二进制兼容性方面兼容,例如,通过检查兼容的编译时设置,包括 32/64 位二进制文件。任何外部模块也必须二进制兼容,这一点很重要,尽管 pg_upgrade 无法检查这一点。

pg_upgrade 支持从 9.2.X 及更高版本升级到 PostgreSQL 的当前主版本,包括快照版本和 beta 版本。

警告

升级集群会导致目标服务器执行源超级用户选择的任意代码。在升级前,请确保源超级用户是受信任的。

选项

pg_upgrade 接受以下命令行参数:

-b bindir
--old-bindir=bindir

旧 PostgreSQL 可执行文件目录;环境变量 PGBINOLD

-B bindir
--new-bindir=bindir

新 PostgreSQL 可执行文件目录;默认是 pg_upgrade 所在的目录;环境变量 PGBINNEW

-c
--check

仅检查集群,不更改任何数据。

-d configdir
--old-datadir=configdir

旧数据库集群配置目录;环境变量 PGDATAOLD

-D configdir
--new-datadir=configdir

新数据库集群配置目录;环境变量 PGDATANEW

-j njobs
--jobs=njobs

要使用的并发连接和进程/线程数。

-k
--link

使用硬链接而不是将文件复制到新集群。

-N
--no-sync

默认情况下,pg_upgrade 会等待所有已升级集群的文件安全写入磁盘。此选项导致 pg_upgrade 在不等待的情况下返回,这样更快,但意味着后续的操作系统崩溃可能会导致数据目录损坏。通常,此选项对测试很有用,但不应在生产环境中使用。

-o options
--old-options options

要直接传递给旧 postgres 命令的选项;多个选项调用会被追加。

-O options
--new-options options

要直接传递给新 postgres 命令的选项;多个选项调用会被追加。

-p port
--old-port=port

旧集群的端口号;环境变量 PGPORTOLD

-P port
--new-port=port

新集群的端口号;环境变量 PGPORTNEW

-r
--retain

即使升级成功,也保留 SQL 和日志文件。

-s dir
--socketdir=dir

升级期间用于 postmaster 套接字(socket)的目录;默认是当前工作目录;环境变量 PGSOCKETDIR

-U username
--username=username

集群的安装用户名;环境变量 PGUSER

-v
--verbose

启用详细的内部日志记录。

-V
--version

显示版本信息,然后退出。

--clone

使用高效的文件克隆(在某些系统上称为“reflinks”)而不是将文件复制到新集群。这可以实现近乎即时的复制数据文件,提供 -k/--link 的速度优势,同时保持旧集群不变。

文件克隆仅在某些操作系统和文件系统上受支持。如果选择了克隆但不支持,pg_upgrade 运行将报错。目前,它支持 Linux(内核 4.5 或更高版本)上的 Btrfs 和 XFS(在创建时支持 reflink 的文件系统上),以及 macOS 上的 APFS。

--copy

将文件复制到新集群。这是默认选项。(另请参阅 --link--clone--copy-file-range--swap。)

--copy-file-range

使用 copy_file_range 系统调用进行高效复制。在某些文件系统上,这会产生类似于 --clone 的结果,共享物理磁盘块,而在其他文件系统上,它可能仍然复制块,但通过优化路径进行。目前,它在 Linux 和 FreeBSD 上受支持。

--no-statistics

不要将统计信息从旧集群还原到新集群。

--set-char-signedness=option

手动设置新集群的默认 char 类型有符号/无符号行为。可能的值为 signedunsigned

在 C 语言中,char 类型的默认有符号/无符号行为(当未明确指定时)因平台而异。例如,在 x86 CPU 上 char 默认为 signed char,而在 ARM CPU 上则默认为 unsigned char

从 PostgreSQL 18 开始,数据库集群维护自己的默认 char 有符号/无符号设置,可用于确保在具有不同默认 char 有符号/无符号行为的平台上实现一致的行为。默认情况下,pg_upgrade 在从现有集群升级时会保留 char 有符号/无符号设置。但是,当从 PostgreSQL 17 或更早版本升级时,pg_upgrade 会采用其构建平台的 char 有符号/无符号行为。

此选项允许您显式设置新集群的默认 char 有符号/无符号行为,从而覆盖任何继承的值。以下是此选项相关的两种特定场景:

  • 如果您计划在升级后迁移到其他平台,则不应使用此选项。默认行为在这种情况下是正确的。请在原始平台上使用此标志进行升级,然后再迁移集群。这是推荐且最安全的方法。

  • 如果您已将集群迁移到具有不同 char 有符号/无符号行为的平台(例如,从基于 x86 的系统迁移到基于 ARM 的系统),则应使用此选项指定与原始平台默认 char 有符号/无符号行为匹配的设置。此外,在迁移数据文件和运行 pg_upgrade 之间,不得修改任何数据文件。pg_upgrade 应该是在新平台上启动集群的第一个操作。

--swap

将数据目录从旧集群移到新集群。然后,用为新集群生成的目录替换目录文件。此模式的性能可能优于 --link--clone--copy--copy-file-range,尤其是在包含大量关系(relations)的集群中。

但是,此模式会在旧集群中创建许多垃圾文件,如果使用 --sync-method=syncfs,这会延长文件同步步骤。因此,建议在 --swap 中使用 --sync-method=fsync

此外,一旦文件传输步骤开始,旧集群将被破坏性修改,因此不再可以安全启动。有关详细信息,请参阅 第 17 步

--sync-method=method

当设置为 fsync(默认值)时,pg_upgrade 将递归地打开并同步已升级集群数据目录中的所有文件。文件搜索将遵循 WAL 目录和每个配置的表空间(tablespace)的符号链接。

在 Linux 上,还可以使用 syncfs 来请求操作系统同步包含已升级集群数据目录、WAL 文件和每个表空间的整个文件系统。有关使用 syncfs 时需要注意的注意事项,请参阅 recovery_init_sync_method

当使用 --no-sync 时,此选项无效。

-?
--help

显示帮助信息,然后退出。

用法

以下是使用 pg_upgrade 进行升级的步骤:

注意

此处不涵盖升级 逻辑复制集群的步骤;有关详细信息,请参阅 第 29.13 节

  1. 可选:移动旧集群

    如果您使用的是按版本安装的目录,例如 /opt/PostgreSQL/18,则不需要移动旧集群。所有图形安装程序都使用按版本安装的目录。

    如果您的安装目录不是按版本区分的,例如 /usr/local/pgsql,则必须移动当前的 PostgreSQL 安装目录,以避免与新 PostgreSQL 安装冲突。一旦当前的 PostgreSQL 服务器已关闭,就可以安全地重命名 PostgreSQL 安装目录;假设旧目录是 /usr/local/pgsql,您可以这样做:

    mv /usr/local/pgsql /usr/local/pgsql.old
    

    来重命名目录。

  2. 对于从源代码安装的情况,构建新版本

    使用与旧集群兼容的 configure 标志构建新的 PostgreSQL 源代码。pg_upgrade 将检查 pg_controldata 以确保所有设置在开始升级前都是兼容的。

  3. 安装新的 PostgreSQL 二进制文件

    安装新的服务器二进制文件和支持文件。pg_upgrade 包含在默认安装中。

    对于源代码安装,如果您希望将新服务器安装在自定义位置,请使用 prefix 变量:

    make prefix=/usr/local/pgsql.new install
    
  4. 初始化新的 PostgreSQL 集群

    使用 initdb 初始化新集群。同样,使用与旧集群匹配的兼容 initdb 标志。许多预编译的安装程序会自动执行此步骤。无需启动新集群。

  5. 安装扩展共享对象文件

    许多扩展和自定义模块,无论是来自 contrib 还是其他来源,都使用共享对象文件(或 DLL),例如 pgcrypto.so。如果旧集群使用了这些文件,则必须将与新服务器二进制文件匹配的共享对象文件安装到新集群中,通常通过操作系统命令完成。不要加载模式定义,例如 CREATE EXTENSION pgcrypto,因为这些定义将从旧集群复制过来。如果有可用的扩展更新,pg_upgrade 将报告此情况并创建一个脚本,该脚本稍后可以运行以更新它们。

  6. 复制自定义全文搜索文件

    将任何自定义全文搜索文件(字典、同义词、词汇表、停用词)从旧集群复制到新集群。

  7. 调整身份验证

    pg_upgrade 将连接到旧服务器和新服务器几次,因此您可能希望在 pg_hba.conf 中将身份验证设置为 peer,或者使用 ~/.pgpass 文件(请参阅 第 32.16 节)。

  8. 停止两个服务器

    确保两个数据库服务器都已停止。在 Unix 系统上,例如使用:

    pg_ctl -D /opt/PostgreSQL/12 stop
    pg_ctl -D /opt/PostgreSQL/18 stop
    

    或在 Windows 上,使用正确的服务名称:

    NET STOP postgresql-12
    NET STOP postgresql-18
    

    流复制(streaming replication)和日志寄送(log-shipping)备用服务器在此关闭期间必须运行,以便它们接收所有更改。

  9. 准备备用服务器升级

    如果您正在使用第 11 步中概述的方法升级备用服务器,请通过在旧主服务器和备用服务器集群上运行 pg_controldata 来验证旧备用服务器是否已同步。验证所有集群中的“最新检查点位置”值是否匹配。另外,请确保新主集群的 postgresql.conf 文件中的 wal_level 未设置为 minimal

  10. 运行 pg_upgrade

    始终运行新服务器的 pg_upgrade 二进制文件,而不是旧服务器的。pg_upgrade 需要指定旧集群和新集群的数据目录和可执行文件(bin)目录。您还可以指定用户和端口号,以及您希望数据文件链接、克隆或交换而不是默认复制行为。

    如果您使用链接模式,升级将更快(无需复制文件)且占用更少的磁盘空间,但在升级后启动新集群后,您将无法访问旧集群。链接模式还要求旧集群和新集群的数据目录在同一个文件系统上。(表空间和 pg_wal 可以在不同的文件系统上。)克隆模式提供相同的速度和磁盘空间优势,但不会导致在新集群启动后旧集群不可用。克隆模式也要求旧集群和新集群的数据目录在同一个文件系统上。此模式仅在某些操作系统和文件系统上可用。如果关系很多,交换模式(swap mode)可能是最快的,但在文件传输步骤开始后,您将无法访问旧集群。交换模式还要求旧集群和新集群的数据目录在同一个文件系统上。

    --jobs 设置为 2 或更高,允许 pg_upgrade 并行处理多个数据库和表空间。一个好的起点是机器上的 CPU 核心数。此选项可以显著减少多数据库和多表空间服务器的升级时间。

    对于 Windows 用户,您必须登录到管理员帐户,然后使用带引号的目录运行 pg_upgrade,例如:

    pg_upgrade.exe
            --old-datadir "C:/Program Files/PostgreSQL/12/data"
            --new-datadir "C:/Program Files/PostgreSQL/18/data"
            --old-bindir "C:/Program Files/PostgreSQL/12/bin"
            --new-bindir "C:/Program Files/PostgreSQL/18/bin"
    

    启动后,pg_upgrade 将验证两个集群是否兼容,然后执行升级。您可以使用 pg_upgrade --check 来仅执行检查,即使旧服务器仍在运行。pg_upgrade --check 还会概述您在升级后需要进行的任何手动调整。如果您打算使用链接、克隆、copy-file-range 或交换模式,则应将 --link--clone--copy-file-range--swap 选项与 --check 一起使用,以启用特定模式的检查。pg_upgrade 需要在当前目录中具有写入权限。

    显然,在升级期间不应有人访问集群。pg_upgrade 默认使用端口 50432 运行服务器,以避免意外的客户端连接。您可以在升级时对两个集群使用相同的端口号,因为旧集群和新集群不会同时运行。但是,在检查正在运行的旧服务器时,旧端口号和新端口号必须不同。

    如果在还原数据库模式时发生错误,pg_upgrade 将退出,您必须按照下面的 第 17 步中的说明恢复到旧集群。要再次尝试 pg_upgrade,您需要修改旧集群,以便 pg_upgrade 模式还原能够成功。如果问题是 contrib 模块,您可能需要从旧集群卸载 contrib 模块,并在升级后将其安装到新集群中,前提是该模块不用于存储用户数据。

  11. 升级流复制和日志寄送备用服务器

    如果您使用了链接模式,并且拥有流复制(参见 第 26.2.5 节)或日志寄送(参见 第 26.2 节)备用服务器,您可以按照以下步骤快速升级它们。您不会在备用服务器上运行 pg_upgrade,而是在主服务器上运行 rsync。请勿启动任何服务器。

    如果您没有使用链接模式,或者不拥有/不想使用 rsync,或者想要一个更简单的解决方案,请跳过本节中的说明,并在 pg_upgrade 完成且新主服务器正在运行时重新创建备用服务器。

    1. 在备用服务器上安装新的 PostgreSQL 二进制文件

      确保在新备用服务器上安装了新的二进制文件和支持文件。

    2. 确保新的备用服务器数据目录不存在

      确保新的备用服务器数据目录不存在或为空。如果运行了 initdb,请删除备用服务器的新数据目录。

    3. 安装扩展共享对象文件

      在新备用服务器上安装与新主集群相同的扩展共享对象文件。

    4. 停止备用服务器

      如果备用服务器仍在运行,请使用上述说明现在停止它们。

    5. 保存配置文件

      保存旧备用服务器配置目录中您需要保留的任何配置文件,例如 postgresql.conf(及其包含的任何文件)、postgresql.auto.confpg_hba.conf,因为它们将在下一步中被覆盖或删除。

    6. 运行 rsync

      当使用链接模式时,备用服务器可以使用 rsync 快速升级。为此,在主服务器上高于旧集群和新集群数据目录的某个目录中,在主服务器上为每个备用服务器运行此命令:

      rsync --archive --delete --hard-links --size-only --no-inc-recursive old_cluster new_cluster remote_dir
      

      其中 old_clusternew_cluster 相对于主服务器上的当前目录,而 remote_dir 是备用服务器上高于旧集群和新集群目录的目录。主服务器和备用服务器上指定目录下的目录结构必须匹配。有关指定远程目录的详细信息,请查阅 rsync 的手册页,例如:

      rsync --archive --delete --hard-links --size-only --no-inc-recursive /opt/PostgreSQL/12 \
            /opt/PostgreSQL/18 standby.example.com:/opt/PostgreSQL
      

      您可以使用 rsync--dry-run 选项来验证该命令将执行的操作。虽然 rsync 必须在主服务器上至少为一个备用服务器运行,但也可以在已升级的备用服务器上运行 rsync 来升级其他备用服务器,前提是已升级的备用服务器尚未启动。

      此操作记录了 pg_upgrade 的链接模式在主服务器上创建的连接旧集群和新集群之间文件的链接。然后,它在备用服务器的旧集群中查找匹配的文件,并在备用服务器的新集群中为它们创建链接。在主服务器上未链接的文件将从主服务器复制到备用服务器。(它们通常很小。)这提供了快速的备用服务器升级。不幸的是,rsync 会不必要地复制与临时表和未记录表(unlogged tables)相关的文件的链接,因为这些文件通常在备用服务器上不存在。

      如果您有表空间,您将需要为每个表空间目录运行类似的 rsync 命令,例如:

      rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tblsp/PG_12_201909212 \
            /vol1/pg_tblsp/PG_18_202307071 standby.example.com:/vol1/pg_tblsp
      

      如果您已将 pg_wal 目录移出数据目录,也必须在这些目录上运行 rsync

    7. 配置流复制和日志寄送备用服务器

      配置服务器进行日志寄送。(您不需要运行 pg_backup_start()pg_backup_stop() 或进行文件系统备份,因为备用服务器仍与主服务器同步。)如果旧主服务器的版本低于 17.0,那么主服务器上的插槽(slots)不会复制到新备用服务器,因此所有旧备用服务器上的插槽都必须手动重新创建。如果旧主服务器是 17.0 或更高版本,那么只有主服务器上的逻辑插槽会被复制到新备用服务器,但旧备用服务器上的其他插槽不会被复制,因此必须手动重新创建。

  12. 恢复 pg_hba.conf

    如果您修改了 pg_hba.conf,请恢复其原始设置。可能还需要调整新集群中的其他配置文件以匹配旧集群,例如 postgresql.conf(及其包含的任何文件)、postgresql.auto.conf

  13. 启动新服务器

    现在可以安全地启动新服务器,然后启动任何通过 rsync 复制的备用服务器。

  14. 升级后处理

    如果需要进行任何升级后处理,pg_upgrade 将在其完成时发出警告。它还将生成必须由管理员运行的脚本文件。脚本文件将连接到每个需要进行升级后处理的数据库。每个脚本都应使用以下命令运行:

    psql --username=postgres --file=script.sql postgres
    

    脚本可以按任何顺序运行,并且在运行后可以删除。

    注意

    通常情况下,在重建脚本运行完成之前访问脚本引用的表是不安全的;这样做可能导致不正确的结果或性能低下。未在重建脚本中引用的表可以立即访问。

  15. 统计信息

    除非指定了 --no-statistics 选项,否则 pg_upgrade 将将大多数优化器统计信息从旧集群传输到新集群。但是,某些统计信息可能不会被传输,例如那些使用 CREATE STATISTICS 显式创建的统计信息或扩展添加的自定义统计信息。

    由于 pg_upgrade 不会传输所有统计信息,因此在升级结束时,您将被指示运行命令来重新生成这些信息。您可能需要设置连接参数以匹配新集群。

    首先,使用 vacuumdb --all --analyze-in-stages --missing-stats-only 为没有任何统计信息的表快速生成最小优化器统计信息。然后,使用 vacuumdb --all --analyze-only 来确保所有关系都具有最新的累积统计信息,以触发 vacuum 和 analyze。对于这两个命令,使用 --jobs 可以加快速度。如果 vacuum_cost_delay 设置为非零值,可以使用 PGOPTIONS 进行覆盖以加快统计信息生成,例如 PGOPTIONS='-c vacuum_cost_delay=0' vacuumdb ...

  16. 删除旧集群

    一旦您对升级满意,就可以通过运行 pg_upgrade 完成时提到的脚本来删除旧集群的数据目录。(如果旧数据目录中包含用户定义的表空间,则无法自动删除。)您还可以删除旧的安装目录(例如 binshare)。

  17. 恢复到旧集群

    如果在运行 pg_upgrade 后,您希望恢复到旧集群,有以下几种选择:

    • 如果使用了 --check 选项,旧集群未被修改;可以重新启动它。

    • 如果既未使用 --link 也未使用 --swap,则旧集群未被修改;可以重新启动它。

    • 如果使用了 --link 选项,则数据文件可能在旧集群和新集群之间共享。

      • 如果 pg_upgrade 在链接开始前中止,旧集群未被修改;可以重新启动它。

      • 如果您没有启动新集群,旧集群未被修改,除了在链接开始时,$PGDATA/global/pg_control 追加了 .old 后缀。要重新使用旧集群,请从 $PGDATA/global/pg_control 中删除 .old 后缀;然后您可以重新启动旧集群。

      • 如果您启动了新集群,它已经写入了共享文件,使用旧集群是不安全的。在这种情况下,需要从备份中恢复旧集群。

    • 如果使用了 --swap 选项,旧集群可能已被破坏性修改。

      • 如果 pg_upgrade 在报告旧集群不再安全启动之前中止,则旧集群未被修改;可以重新启动它。

      • 如果 pg_upgrade 已报告旧集群不再安全启动,则旧集群已被破坏性修改。在这种情况下,需要从备份中恢复旧集群。

环境变量

一些环境变量可用于为命令行选项提供默认值:

PGBINOLD

旧 PostgreSQL 可执行文件目录;选项 -b/--old-bindir

PGBINNEW

新 PostgreSQL 可执行文件目录;选项 -B/--new-bindir

PGDATAOLD

旧数据库集群配置目录;选项 -d/--old-datadir

PGDATANEW

新数据库集群配置目录;选项 -D/--new-datadir

PGPORTOLD

旧集群的端口号;选项 -p/--old-port

PGPORTNEW

新集群的端口号;选项 -P/--new-port

PGSOCKETDIR

升级期间用于 postmaster 套接字(socket)的目录;选项 -s/--socketdir

PGUSER

集群的安装用户名;选项 -U/--username

注释

pg_upgrade 在新集群的目录下创建各种工作文件,如模式转储。pg_upgrade_output.d 目录中,每次运行都会创建一个带有根据 ISO 8601 格式化(%Y%m%dT%H%M%S)的时间戳的新子目录,所有生成的文件都存储在那里。pg_upgrade_output.d 及其包含的文件将在 pg_upgrade 成功完成后自动删除;但如果出现问题,那里存储的文件可能提供有用的调试信息。

pg_upgrade 在旧数据目录和新数据目录中启动短暂的 postmaster。用于与这些 postmaster 通信的临时 Unix 套接字文件默认是在当前工作目录中创建的。在某些情况下,当前目录的路径名可能太长,无法作为有效的套接字名称。在这种情况下,您可以使用 -s 选项将套接字文件放在一个路径名较短的目录中。出于安全考虑,请确保该目录不被其他任何用户读取或写入。(在 Windows 上不支持此功能。)

所有失败、重建和重新索引的情况都会由 pg_upgrade 报告(如果它们影响您的安装);重建表和索引的升级后脚本将自动生成。如果您试图自动化许多集群的升级,您会发现具有相同数据库模式的集群需要对所有集群升级执行相同的升级后步骤;这是因为升级后步骤基于数据库模式,而不是用户数据。

对于部署测试,请创建旧集群的仅模式副本,插入虚拟数据,然后升级它。

pg_upgrade 不支持升级包含使用这些 reg* OID 引用系统数据类型的表列的数据库。

regcollation
regconfig
regdictionary
regnamespace
regoper
regoperator
regproc
regprocedure

regclassregroleregtype 可以升级。)

如果您想使用链接模式,并且不希望在新集群启动时修改旧集群,可以考虑使用克隆模式。如果该模式不可用,请复制旧集群并在链接模式下进行升级。要制作旧集群的有效副本,请在服务器运行时使用 rsync 创建旧集群的脏副本,然后关闭旧服务器并再次运行 rsync --checksum 以更新副本中的更改,使其一致。(--checksum 是必需的,因为 rsync 的文件修改时间粒度只有一秒。)您可能需要排除某些文件,例如 postmaster.pid,如 第 25.3.4 节中所述。如果您的文件系统支持文件系统快照或写时复制(copy-on-write)文件复制,您可以使用它来备份旧集群和表空间,尽管快照和副本必须同时创建或在数据库服务器关闭期间创建。

另请参阅

initdbpg_ctlpg_dumppostgres

提交更正

如果您在文档中发现任何不正确之处,与您对特定功能的实际体验不符,或者需要进一步澄清,请使用 此表格 来报告文档问题。