4. 逻辑备份与恢复工具选型

PostgreSQL 的逻辑备份工具并非“一个命令走天下”。pg_dump、pg_dumpall、pg_restore、COPY 四者面向的对象层级、并发模型、一致性快照机制和恢复粒度差异很大。选型错误往往不会在备份时暴露,而是在恢复现场才集中爆发:要么恢复不出全局角色导致应用连不上,要么单表恢复被迫重放整库,要么并行度上不去导致窗口超时。本节先厘清四者的能力边界,再给出可落地的备份策略组合。

四类工具的能力边界

pg_dump 是单数据库逻辑导出工具,导出对象包括表结构、数据、索引、约束、触发器、函数、序列当前值等,但不包含角色、表空间定义和数据库本身的创建语句。它支持 -Fc(自定义格式)、-Fd(目录格式)、-Ft(tar)、-Fp(纯 SQL)四种输出。其中只有目录格式 -Fd 支持 -j 并行导出,因为并行导出的本质是多个工作进程各自导出一部分表,再写入独立文件。

pg_dumpall 是集群级导出工具,核心价值在于导出全局对象:角色、表空间、以及各数据库的创建语句。它内部对每个数据库仍调用 pg_dump,因此单库部分可以并行,但全局对象部分(--globals-only)是串行的。它默认输出纯 SQL 脚本,恢复时用 psql 顺序执行,无法使用 pg_restore 的并行恢复能力。

pg_restore 不是备份工具,而是 pg_dump 自定义/目录/tar 格式的恢复工具。它的关键能力是选择性恢复(-t 指定表、-n 指定模式、-l 列出归档内容)和并行恢复(-j)。并行恢复对目录格式最有效,因为每个表的数据文件相互独立,多个进程可以同时 COPY 入库。

COPY 是表级数据搬运命令,服务端 COPY 与客户端 \copy 均可。它只处理数据行,不处理 DDL、索引、约束、权限。优势是速度极快、格式灵活(CSV、二进制),适合大批量数据导入导出、跨库表级同步、以及 ETL 中间环节。它不提供跨表一致性快照,除非显式包在 BEGIN ... REPEATABLE READ 事务中。

一致性保证的差异

pg_dump 默认在导出开始时开启一个可重复读事务(REPEATABLE READ),因此同一数据库内所有表的导出数据来自同一个快照,具备库内一致性。但要注意:pg_dump 不保证跨数据库一致性,因为每个数据库是独立连接、独立快照。pg_dumpall 逐库导出,各库快照时间点不同,因此集群级备份不具备全局一致性。COPY 单独执行时每条语句各自快照,多表导出若不在同一事务内,可能出现表间数据时间点不一致。

若业务要求“订单表与订单明细表必须同一时刻”,应使用 pg_dump 单库导出,而不是分别 COPY 两张表。若要求“多个数据库之间一致”,逻辑备份无法满足,需改用 pg_basebackup 物理备份或文件系统快照。

并行能力与恢复粒度对照

工具导出并行恢复并行恢复粒度包含全局对象
pg_dump -Fd支持 -j需配合 pg_restore -j库 / 模式 / 表否
pg_dump -Fc不支持pg_restore -j 支持库 / 模式 / 表否
pg_dumpall仅单库部分psql 串行集群 / 库是
COPY需自行分片需自行分片表 / 行否

并行度并非越高越好。pg_restore -j 的每个工作进程都会占用一个数据库连接并产生 WAL 写入压力,通常建议 -j 不超过 CPU 核数,且恢复期间监控 pg_stat_activity 与 WAL 生成速率。对于含大量小表的库,并行收益有限;对于少数超大表,并行恢复提升明显。

选型决策与策略组合

实际生产环境很少只用一种工具,常见组合是:pg_dumpall --globals-only 负责角色与表空间定义,pg_dump -Fd -j 负责各业务库数据,两者配合 pg_restore -j 完成快速恢复。对于超大规模单表或跨库数据交换,用 COPY 做补充。下面这张图展示了从备份对象到工具选择、再到恢复路径的对应关系。

逻辑备份工具选型与恢复路径 全局对象 角色 / 表空间 / 建库 单库全对象 表 / 索引 / 函数 / 序列 表级数据 行数据 / CSV / 二进制 跨库交换 ETL / 表同步 pg_dumpall --globals-only pg_dump -Fd -j 并行导出 COPY 服务端 / 客户端 pg_restore -j 并行恢复 psql 执行 先建角色与表空间 pg_restore -j 目录格式并行恢复 COPY 导入 表级快速装载 选择性恢复 -t 表 / -n 模式 一致性快照范围 pg_dump:单库内 REPEATABLE READ 快照,库内一致;跨库不一致 pg_dumpall:逐库独立快照,集群级不一致;COPY:单语句快照,多表需显式事务包裹

制定备份策略的实操要点

一个可执行的策略至少回答四个问题:备份什么、用什么工具、多久一次、如何验证。以下给出一个面向中等规模业务库的示例配置,参数属于教学示例,实际需按数据量与窗口调整。

# 1. 全局对象备份(每日一次,保留 30 天)
pg_dumpall -h 10.0.0.10 -p 5432 -U postgres \
  --globals-only -f /backup/globals_$(date +%F).sql

# 2. 业务库目录格式并行导出(每日一次)
pg_dump -h 10.0.0.10 -p 5432 -U postgres \
  -Fd -j 4 -f /backup/orderdb_$(date +%F) orderdb

# 3. 恢复:先全局对象,再并行恢复业务库
psql -h 10.0.0.20 -U postgres -f /backup/globals_2025-01-15.sql
pg_restore -h 10.0.0.20 -U postgres -d orderdb \
  -j 4 --no-owner /backup/orderdb_2025-01-15

# 4. 单表应急恢复(从目录格式中只取一张表)
pg_restore -h 10.0.0.20 -U postgres -d orderdb \
  -t public.orders --data-only /backup/orderdb_2025-01-15

验证环节不可省略。备份完成后至少做三件事:用 pg_restore -l 确认归档目录可读且对象数量符合预期;在测试实例上实际恢复一次并比对关键表行数;记录备份耗时与恢复耗时,作为窗口规划依据。对于 COPY 导出的 CSV,恢复前应确认目标表已存在且列顺序一致,否则会因列错位导致数据污染。

若备份窗口紧张,优先把 pg_dump 改为 -Fd -j 目录格式,恢复时同样用 -j 并行,通常比纯 SQL 脚本快数倍。全局对象单独用 pg_dumpall --globals-only 每日导出,体积小、恢复快,不必与业务库数据捆绑。

最后强调恢复粒度的选择逻辑:需要整库回滚用 pg_dump + pg_restore;需要跨集群重建用 pg_dumpall + psql;只需要一张表或一个模式用 pg_restore -t/-n;只需要数据行、不需要 DDL 用 COPY。把工具能力与恢复目标对齐,备份策略才真正可用。