pg_restore 恢复
pg_dump 有四种输出格式,其中三种(custom、directory、tar)是归档格式——它们不是可以直接喂给 psql 的 SQL 脚本,而是带有「对象目录(TOC)」的结构化容器。恢复这类归档必须用 pg_restore。
pg_restore 的价值远不止「把归档还原成库」。它有两种工作模式:直接连库恢复(-d dbname)和生成 SQL 脚本(不指定 -d,输出到文件或标准输出)。前者支持并行恢复(-j)、单事务恢复、按 section 分阶段恢复;后者让你在真正执行之前完整审阅即将运行的 SQL,或者把归档转成纯文本以便人工修改。
更关键的是「选择性恢复」:归档里记录了每一项对象(表、索引、约束、数据、大对象……)的条目,pg_restore -l 可以列出这份清单,导出成文本、编辑、再用 -L 按编辑后的清单与顺序恢复。这是「只找回一张表」「跳过某个索引」「调整恢复顺序」这类需求的实现方式。
前置知识
建议先阅读:pg_dumpall 全集群备份、pg_dump 基础用法
基础概念
pg_restore 的适用边界
| 归档格式 | 用 pg_restore 恢复 | 用 psql 恢复 |
|---|---|---|
plain(-Fp) | ✗ 不支持 | ✔ 唯一方式 |
custom(-Fc) | ✔ | ✗ |
directory(-Fd) | ✔ | ✗ |
tar(-Ft) | ✔ | ✗ |
判断依据很简单:归档格式是二进制 / 结构化的,必须由 pg_restore 解释。反过来,pg_dumpall 的输出永远是纯文本,只能用 psql。
两种工作模式
# 模式一:直接恢复到数据库
pg_restore -h host -U user -d mydb /backup/mydb.dump
# 模式二:生成 SQL 脚本(不指定 -d)
pg_restore -f mydb.sql /backup/mydb.dump两种模式的能力差异很大:
| 能力 | 直接连库(-d) | 生成脚本(无 -d) |
|---|---|---|
并行 -j | ✔ | ✗(被忽略) |
单事务 -1 | ✔ | 无意义 |
--disable-triggers | ✔ | ✔(输出到脚本) |
--no-data-for-failed-tables | ✔ | ✗ |
| 恢复失败时的错误统计 | ✔ | 不适用 |
| 人工审阅 / 修改 SQL | ✗ | ✔ |
生成脚本模式是审阅不可信归档的唯一手段,官方安全警告中明确提到这一点:先用 --file 把归档转成文本,检查过再执行。
TOC:归档的目录清单
每个归档内部都有一份「目录表(Table of Contents)」,记录每一项待恢复对象的类型、OID、所属、名称、属主。pg_restore -l 就是把这份清单打印出来:
;
; Archive created at 2026-09-30 10:12:33 CST
; dbname: orders
; TOC Entries: 42
; Compression: zstd
; Dump Version: 1.15-0
; Format: CUSTOM
; Integer: 4 bytes
; Offset: 8 bytes
; Dumped from database version: 18.0
; Dumped by pg_dump version: 18.0
;
;
; Selected TOC Entries:
;
215; 1259 16385 TABLE public orders postgres
216; 1259 16386 TABLE public order_items postgres
217; 1259 16387 SEQUENCE public orders_id_seq postgres
215; 1259 16388 INDEX public orders_pkey postgres
216; 1259 16389 CONSTRAINT public orders_pkey postgres
3371; 0 16385 TABLE DATA public orders postgres
3372; 0 16386 TABLE DATA public order_items postgres
3373; 0 16387 SEQUENCE SET public orders_id_seq postgres
213; 1259 16390 TRIGGER public trg_orders_audit postgres每一行前面那串数字是「dumpId; 表 OID; 对象 OID」的固定结构,后面是对象类型、schema、名称、属主。这份输出有两个用途:
-l输出可直接作为-L的输入,实现「编辑后按改动的清单恢复」;-l也可以用来判断归档是否完整可读,是备份后最廉价的校验手段。
恢复阶段:pre-data / data / post-data
归档中的对象被划分为三个阶段,pg_restore 默认按此顺序恢复:
| 阶段 | 内容 | 为什么在这一阶段 |
|---|---|---|
pre-data | 表定义、序列定义、类型、函数、schema、扩展 | 必须先有容器 |
data | 表数据、大对象、序列值(setval) | 需要表已存在 |
post-data | 索引、约束(主键 / 外键 / 检查)、触发器、规则 | 先灌数据再建索引更快,外键也才不会被逐行校验 |
理解这个顺序是排查恢复问题的关键。例如「恢复后外键不存在」往往不是没导,而是 post-data 阶段某条语句失败被跳过了。
为什么并行恢复需要目录格式
-j 会把最耗时的三类步骤——装载数据、创建索引、创建约束——分给多个会话并发执行。并发的前提是各任务之间没有顺序依赖。
custom格式:单个文件,但内部通过 seek 定位各对象,多个 worker 可以访问同一文件的不同偏移,因此支持-j;directory格式:天然每表一个文件,更适合并发;tar格式:单个顺序文件流,无法并行,也不支持-j;- 输入必须是常规文件或目录,不能是管道或标准输入。
关键术语
| 术语 | 含义 |
|---|---|
| 归档(archive) | pg_dump 的 -Fc / -Fd / -Ft 输出,需 pg_restore 读取 |
| TOC | 归档内的对象目录清单,-l 打印、-L 消费 |
-l / -L | 列出清单 / 按指定清单恢复 |
| section | pre-data / data / post-data 三个阶段 |
--role | 恢复期间执行 SET ROLE 切换身份 |
| 依赖对象 | 表所依赖的序列、类型、索引、约束、触发器 |
--strict-names | 过滤模式必须匹配到对象,否则报错 |
row_security | PG18 中 pg_restore 默认置为 off 以完整写入数据 |
语法与用法
基本语法
pg_restore [connection-option...] [option...] [filename]filename 是归档文件(或目录格式的目录)。省略时从标准输入读取。
最简示例
# 恢复到已有数据库
pg_restore -h 10.0.0.5 -U postgres -d orders /backup/orders.dump
# 并行恢复(需归档为 custom / directory 格式)
pg_restore -h 10.0.0.5 -U postgres -d orders -j 8 /backup/orders.dump
# 重建对象(先 DROP 再 CREATE)
pg_restore -h 10.0.0.5 -U postgres -d orders --clean --if-exists /backup/orders.dump
# 由归档创建数据库
pg_restore -h 10.0.0.5 -U postgres -d postgres --create /backup/orders.dump
# 转成 SQL 脚本以便审阅
pg_restore -f /tmp/orders.sql /backup/orders.dump查看与选择清单
| 参数 | 长选项 | 含义 |
|---|---|---|
-l | --list | 列出归档的 TOC |
-L | --use-list | 只恢复清单文件中列出的项,并按其中的顺序 |
-f | --file | 输出到文件(配合 -l 时为清单输出到文件) |
-v | --verbose | 输出详细进度 |
# 清单导出到文件,便于编辑
pg_restore -l /backup/orders.dump > /tmp/toc.txt
# 按编辑后的清单恢复(只保留需要的行)
pg_restore -L /tmp/toc.txt -d orders /backup/orders.dump对象过滤
| 参数 | 长选项 | 含义 |
|---|---|---|
-t | --table | 只恢复指定表(不支持通配符、不能带 schema 名) |
-n | --schema | 只恢复指定 schema 中的对象 |
-N | --exclude-schema | 排除指定 schema |
-I | --index | 只恢复指定索引 |
-P | --function | 只恢复指定函数(须写明参数类型) |
-T | --trigger | 只恢复指定触发器 |
--filter | — | 从文件读取 include / exclude 规则 |
# 只恢复一张表(表名不含 schema;需配 -n 限定 schema)
pg_restore -n public -t orders -d orders /backup/orders.dump
# 只恢复某个 schema
pg_restore -n app -d orders /backup/orders.dump
# 排除审计 schema
pg_restore -N audit -d orders /backup/orders.dump
# 只恢复一个索引定义
pg_restore -I orders_pkey -d orders /backup/orders.dumppg_restore -t 与 pg_dump -t 的行为不一致,务必注意三点差异:
pg_restore -t不支持通配符;pg_restore -t不能包含 schema 名,要限定 schema 需另加-n;pg_restore -t不会带上附属对象(索引、约束、触发器),而pg_dump -t会。
也就是说:pg_restore -t orders 恢复出来的是「表定义 + 数据」,索引和主键不会跟着回来。要拿到完整表,用 -L 清单方式更可靠。
内容选择
| 参数 | 长选项 | 含义 |
|---|---|---|
-a | --data-only | 只恢复数据(含表数据、大对象、序列值) |
-s | --schema-only | 只恢复定义,不含数据与统计信息 |
--section | — | 指定阶段:pre-data / data / post-data,可重复 |
--no-data | — | 不恢复数据 |
--no-schema | — | 不恢复定义 |
--no-statistics | — | 不恢复统计信息 |
--no-comments | — | 不恢复注释 |
--no-policies | — | 不恢复 RLS 策略 |
--no-publications / --no-subscriptions | — | 不恢复发布 / 订阅 |
--no-tablespaces | — | 不指定表空间,全部建在默认表空间 |
# 先建结构
pg_restore -d orders --section=pre-data /backup/orders.dump
# 再灌数据
pg_restore -d orders --section=data /backup/orders.dump
# 最后建索引与约束
pg_restore -d orders --section=post-data /backup/orders.dump覆盖与建库
| 参数 | 长选项 | 含义 |
|---|---|---|
-c | --clean | 恢复前先 DROP 将被恢复的对象 |
--if-exists | — | DROP 时加 IF EXISTS,须与 --clean 同用 |
-C | --create | 先创建数据库再恢复进去 |
-O | --no-owner | 不设置属主,对象归恢复者所有 |
-x | --no-privileges | 不恢复 GRANT / REVOKE |
--role | — | 恢复期间 SET ROLE 到指定角色 |
# 完整覆盖式恢复
pg_restore -d orders --clean --if-exists --create /backup/orders.dump
# 跨环境恢复:不带属主与权限
pg_restore -d orders --no-owner --no-privileges /backup/orders.dump
# 以指定角色身份恢复(连接用户需是该角色的成员)
pg_restore -d orders --role=app_owner /backup/orders.dump-C 的一个细节:使用 --create 时,-d 指定的库仅用于执行最初的 DROP DATABASE 与 CREATE DATABASE,实际数据会被恢复到归档中记录的数据库名里。所以 -d postgres + --create 是标准写法。
事务与错误控制
| 参数 | 长选项 | 含义 |
|---|---|---|
-1 | --single-transaction | 整个恢复包在一个事务内,隐含 --exit-on-error |
-e | --exit-on-error | 遇到错误立即退出,默认是继续并最后统计错误数 |
--disable-triggers | — | 数据装载期间临时禁用触发器(需超级用户) |
--no-data-for-failed-tables | — | 建表失败的表的数据不再恢复 |
--enable-row-security | — | 打开 row_security 而不是默认的关闭 |
# 全有或全无的恢复
pg_restore -d orders --single-transaction /backup/orders.dump
# 数据恢复期间禁用触发器(避免逐行触发业务逻辑)
pg_restore -d orders --disable-triggers --section=data /backup/orders.dump
# 目标库已有扩展辅助表,跳过建表失败的表的数据
pg_restore -d orders --no-data-for-failed-tables /backup/orders.dump详细说明
清单编辑流程:-l → 编辑 → -L
这是 pg_restore 最核心的工作流,也是其他工具无法替代的能力。
第一步:导出清单
pg_restore -l /backup/orders.dump > /tmp/toc.txt;
; Archive created at 2026-09-30 10:12:33 CST
; dbname: orders
; TOC Entries: 42
; Compression: zstd
; Format: CUSTOM
;
; Selected TOC Entries:
;
215; 1259 16385 TABLE public orders postgres
216; 1259 16386 TABLE public order_items postgres
217; 1259 16387 SEQUENCE public orders_id_seq postgres
215; 1259 16388 INDEX public orders_pkey postgres
3371; 0 16385 TABLE DATA public orders postgres
3372; 0 16386 TABLE DATA public order_items postgres
3373; 0 16387 SEQUENCE SET public orders_id_seq postgres第二步:编辑清单
保留所需要的行;不需要的行可以删除,也可以在行首加 ; 注释掉。恢复顺序完全由文件中的行序决定,因此还可以通过移动行来调整顺序(例如把某个索引提前建)。
; 只恢复订单表本身,跳过明细表
215; 1259 16385 TABLE public orders postgres
3371; 0 16385 TABLE DATA public orders postgres
; 这行被注释掉,不会恢复
;3372; 0 16386 TABLE DATA public order_items postgres第三步:按清单恢复
pg_restore -L /tmp/toc.txt -d orders /backup/orders.dump要点:
-L可以与-n/-t等过滤参数同时使用,此时过滤条件会进一步收窄清单;- 清单文件里的行必须保持原格式(开头的
dumpId; 表OID 对象OID不能改); - 这是实现「带索引的单表恢复」的正确方式——
-t拿不到索引,-L可以。
并行恢复 -j 的使用条件
pg_restore -d orders -j 8 /backup/orders.dump四条硬性约束:
- 仅
custom与directory格式支持;tar格式不支持; - 输入必须是常规文件或目录,不能是管道或标准输入(并行需要随机访问);
- 不能与
--single-transaction同时使用——两者目标冲突,一个要并发、一个要原子; - 每个 job 是独立进程或线程,各占一条数据库连接,注意
max_connections。
并发值怎么选:官方建议从服务器 CPU 核数起步,很多场景下超过核数反而更快,但过高会因为资源争抢导致性能下降(thrashing)。实际调优时应该用真实数据做几轮压测。
需要注意 -j 只加速三类步骤:装载数据、创建索引、创建约束。pre-data 阶段的对象创建(表、类型、函数)是串行的,因此如果归档里结构极多而数据很少,-j 收益有限。
恢复数据的顺序与约束
这是理解「为什么有些恢复会失败」的关键。
data 阶段默认使用 COPY 装载。如果表上有外键约束,逐行 COPY 会因为「引用的行还不存在」而失败。PostgreSQL 的解决方式是阶段划分:
pre-data : CREATE TABLE(无索引、无外键)
data : COPY 装载数据(此时表上没有外键,不会失败)
post-data: CREATE INDEX + ADD CONSTRAINT(一次性校验,比逐行快得多)所以正常的归档恢复不会遇到外键顺序问题——这正是不用 --single-transaction 时也能正确恢复的原因。
但如果你用 --section=data 手动只恢复数据阶段,就需要确保表与约束已经是最终状态,此时可能踩到外键与唯一约束问题。这时 --disable-triggers 才有意义。
--disable-triggers 的用途与代价
pg_restore -d orders --section=data --disable-triggers /backup/orders.dump它让恢复过程临时关闭目标表上的触发器(外键约束的检查也通过触发器实现),避免在数据装载阶段触发业务逻辑或约束校验。
三个约束条件必须清楚:
- 只在「不带 schema 的恢复」中有意义(即
--section=data或--data-only)。因为默认恢复下外键本来就在post-data阶段才创建; - 执行该命令需要超级用户权限(或通过
-S指定超级用户名); - 它绕过的是触发器层面的检查,不做数据正确性校验,恢复后可能出现违反约束的数据。
一个典型用法:把数据先「硬灌」进库,等数据齐了再统一加约束,这样单行顺序问题就不会中断整个恢复。
--single-transaction 的取舍
pg_restore -d orders --single-transaction /backup/orders.dump收益:要么全部成功,要么全部回滚。目标库不会留下「恢复了一半」的状态。
代价:非常多,务必权衡:
- 整个恢复期间持有一个长事务,会阻止
VACUUM回收,可能造成膨胀; - 隐含
--exit-on-error,任何一条语句失败就整体回滚,而默认模式下几百条「对象已存在」的无害错误不会影响结果; - 不能与
-j并用,失去并行加速; CREATE INDEX会在事务内执行(非CONCURRENTLY),恢复时间可能更长;- 某些语句本身不能在事务块内运行(如
CREATE TABLESPACE、CREATE DATABASE),如果归档中含这类对象会失败。
实践建议:默认不要用 --single-transaction,改用「恢复到临时库 → 校验 → 切换」的两阶段方式获得原子性,同时保留并行能力。
# 推荐:恢复到临时库,校验通过后再改名切换
createdb orders_new
pg_restore -d orders_new -j 8 --no-owner /backup/orders.dump
psql -c 'ALTER DATABASE orders RENAME TO orders_old;'
psql -c 'ALTER DATABASE orders_new RENAME TO orders;'常见恢复错误与处理
依赖对象不存在
表现:function xxx() does not exist、type xxx does not exist、operator does not exist。
根因:用了 -t / -n 做局部恢复,但依赖的类型、函数、扩展没被包含进来。归档本身没问题,是局部恢复的固有局限。
处理:改用 -L 清单方式,把依赖项一起勾选;或先手工创建扩展 / 类型。
属主不存在
ERROR: role "app_user" does not exist处理:目标库没有该角色。两种选择——先建角色,或加 --no-owner。
pg_restore -d orders --no-owner --no-privileges /backup/orders.dump扩展不存在
ERROR: extension "postgis" is not available处理:目标机没装扩展。先安装扩展包,或在源端用 -e 排除特定扩展,或恢复时忽略该错误(默认模式下会继续)。
对象已存在导致的刷屏错误
pg_restore: error: could not execute query: ERROR: relation "orders" already exists处理:这是「恢复到一个已有内容的库」的常见现象。默认模式下属于可忽略错误(结尾会统计错误数)。要清理干净,加 --clean --if-exists。
并行恢复被中止
pg_restore: error: could not find block containing chunk ...或数据加载时出现 unexpected end of file。多见于归档不完整、被截断,或使用了管道。处理:验证归档完整性(pg_restore -l),确认输入是常规文件。
--filter 文件格式
pg_restore -d orders --filter=filter.txt /backup/orders.dump文件格式固定为「动作 + 对象类型 + 模式」:
# 只恢复 app schema 与 orders 表
include schema app
include table public.orders
# 排除审计相关的 schema
exclude schema audit规则要点:
- 动作只有
include/exclude两种; - 对象类型有
function/index/schema/table/trigger; function/index/table/trigger只能与include搭配;只有schema支持exclude;#开头的行是注释,空行忽略;行尾也可以追加注释;--filter可与其他过滤参数并用,也可多次指定;文件名写-表示从标准输入读。
row_security 与恢复完整性
这一点直接关系到「备份数据是否被静默丢行」。
pg_restore 默认会把 row_security 设为 off,目的是确保所有数据都被写进表里——即使恢复账号不是超级用户、也没有 BYPASSRLS,切换为 off 后 PostgreSQL 采取的策略是「宁可报错,也不静默漏行」。
# 默认行为:row_security = off,保证完整写入
pg_restore -d orders /backup/orders.dump如果确实想按 RLS 策略过滤后再恢复:
# 打开 row_security(注意:dump 必须是 INSERT 格式,COPY FROM 不支持 RLS)
pg_restore -d orders --enable-row-security /backup/orders.dump注意 --enable-row-security 的额外限制:因为 COPY FROM 不支持行级安全,所以归档必须是用 --inserts 或 --column-inserts 生成的。这个选项与备份端 pg_dump 的账号权限设置是同一件事的两面,排查「备份丢行」问题时必须同时看两端。
恢复后必做的收尾
恢复完成后有三件事不能忘:
# 1) 更新优化器统计信息(数据是 COPY 进来的,统计信息不会自动准确)
psql -d orders -c 'ANALYZE;'
# 2) 确认序列当前值正确(避免主键冲突)
psql -d orders -c 'SELECT last_value, is_called FROM orders_id_seq;'
# 3) 确认约束与索引都建起来了
psql -d orders -c '\d orders'ANALYZE 尤其重要:恢复的数据没有经过正常的写入路径,pg_statistic 里的信息是旧的甚至不存在,不更新会直接导致恢复后查询计划严重劣化。
实战示例
示例一:标准的整库恢复
#!/usr/bin/env bash
set -euo pipefail
DUMP=/backup/orders.dump
NEWDB=orders_restore
# 1) 校验归档可读
pg_restore -l "$DUMP" > /dev/null
echo "archive ok"
# 2) 建目标库(建议 template0 避免继承 template1 中的对象)
psql -h 10.0.0.5 -U postgres -c "CREATE DATABASE $NEWDB TEMPLATE template0;"
# 3) 并行恢复,不带属主与权限
pg_restore \
-h 10.0.0.5 -U postgres \
-d "$NEWDB" \
-j 8 \
--no-owner --no-privileges \
--verbose \
"$DUMP" 2> /tmp/restore.log
# 4) 收尾
psql -h 10.0.0.5 -U postgres -d "$NEWDB" -c 'ANALYZE;'
echo "restore ok"示例二:只找回一张表及其索引与约束
# 1) 导出清单
pg_restore -l /backup/orders.dump > /tmp/toc.txt
# 2) 只看和 orders 表相关的条目,人工确认要勾选哪些
grep -E 'orders($| )|orders_pkey|orders_tenant' /tmp/toc.txt215; 1259 16385 TABLE public orders postgres
215; 1259 16388 INDEX public orders_pkey postgres
215; 1259 16389 CONSTRAINT public orders_pkey postgres
215; 1259 16390 INDEX public orders_tenant_idx postgres
3371; 0 16385 TABLE DATA public orders postgres
3373; 0 16387 SEQUENCE SET public orders_id_seq postgres# 3) 生成只含这些行的清单
grep -E 'orders($| )|orders_pkey|orders_tenant|TABLE DATA public orders|SEQUENCE SET public orders_id_seq' \
/tmp/toc.txt > /tmp/only_orders.txt
# 4) 按清单恢复
pg_restore -L /tmp/only_orders.txt -d orders /backup/orders.dump这个流程比 pg_restore -t orders 更可靠,因为索引与约束都在清单里被显式包含。
示例三:分阶段恢复以便监控耗时
# 阶段一:结构(通常很快)
time pg_restore -d orders --section=pre-data /backup/orders.dump
# 阶段二:数据(最耗时,可并行)
time pg_restore -d orders --section=data -j 8 /backup/orders.dump
# 阶段三:索引与约束(次耗时,可并行)
time pg_restore -d orders --section=post-data -j 8 /backup/orders.dump分阶段的好处是可以在每个阶段之间插入检查点,也让失败后的重试范围更小——数据阶段失败时不必重跑结构阶段。
示例四:把归档转成 SQL 脚本审阅
# 生成可读脚本
pg_restore --verbose --no-owner -f /tmp/orders_review.sql /backup/orders.dump
# 审阅关键片段
grep -n 'CREATE TABLE' /tmp/orders_review.sql | head -5
grep -c 'COPY ' /tmp/orders_review.sql
grep -n 'ALTER TABLE.*ADD CONSTRAINT' /tmp/orders_review.sql | head -5CREATE TABLE public.orders (
id bigint NOT NULL,
tenant_id integer NOT NULL,
amount numeric(12,2) NOT NULL
);
COPY public.orders (id, tenant_id, amount) FROM stdin;这是官方推荐的安全做法:不可信来源的归档,先用 -f 转成文本审阅,再执行。归档内容可以在恢复时执行任意 SQL,跳过这一步等于把源端的超级用户权限直接搬到目标端。
示例五:用 filter 文件做精细化恢复
cat > /tmp/restore_filter.txt <<'EOF'
# 只恢复业务 schema 与核心表
include schema app
include table public.orders
include table public.order_items
# 排除审计数据
exclude schema audit
EOF
pg_restore -d orders --filter=/tmp/restore_filter.txt \
--no-owner -j 4 /backup/orders.dump示例六:恢复日志中的错误分类统计
pg_restore -d orders /backup/orders.dump 2> /tmp/restore_err.logpg_restore: error: could not execute query: ERROR: role "app_user" does not exist
Command was: ALTER TABLE public.orders OWNER TO app_user;
pg_restore: error: could not execute query: ERROR: role "app_user" does not exist
Command was: ALTER TABLE public.order_items OWNER TO app_user;
pg_restore: warning: errors ignored on restore: 12# 按错误类型归类,判断是「可忽略」还是「必须处理」
grep 'ERROR:' /tmp/restore_err.log | sed 's/.*ERROR: //' | sort | uniq -c | sort -rn 8 role "app_user" does not exist
4 relation "orders" already existsrole does not exist 是属主问题(加 --no-owner 即可消除);already exists 是目标库已有内容(加 --clean --if-exists 或改用空库)。两类都不是数据丢失,属于环境问题。
注意事项
pg_restore 只能读取归档格式
# 错误:plain 格式必须用 psql
pg_restore -d orders /backup/orders.sql
# 正确
psql -d orders -f /backup/orders.sqlpg_restore -t 与 pg_dump -t 行为不同
# 这条只恢复表定义与数据,索引与约束不会回来
pg_restore -n public -t orders -d orders /backup/orders.dump
# 要拿到完整对象,用 -L 清单方式-t 不支持通配符、不能带 schema 名
# 两条都会失败
pg_restore -t 'public.orders_*' -d orders /backup/orders.dump
pg_restore -t 'public.orders' -d orders /backup/orders.dump
# 正确写法:schema 与表名分开
pg_restore -n public -t orders -d orders /backup/orders.dump--if-exists 必须与 --clean 同用
# 无效组合(--if-exists 被忽略)
pg_restore -d orders --if-exists /backup/orders.dump
# 正确
pg_restore -d orders --clean --if-exists /backup/orders.dump-j 不能与 --single-transaction 同用
# 这个组合会报错
pg_restore -d orders -j 8 --single-transaction /backup/orders.dump-j 不能从管道或 stdin 读取
# 错误:并行需要随机访问
cat /backup/orders.dump | pg_restore -d orders -j 8
# 正确:直接给文件路径
pg_restore -d orders -j 8 /backup/orders.dump--clean 会先删对象,误操作代价高
# 危险:目标库里的同名对象会被删掉再重建,期间数据不可用
pg_restore -d production --clean --if-exists /backup/orders.dump在恢复生产库之前,务必确认目标库名正确。--clean 删除的是「归档中存在的对象」,不会删归档外的表,但这也意味着不会清理干净——残留对象可能造成困惑。
-C 恢复的库名来自归档,不是 -d
# 数据会恢复到归档中记录的 "orders" 库,而不是 mytemp
pg_restore -d mytemp --create /backup/orders.dump--disable-triggers 需要超级用户
# 普通用户执行会失败
pg_restore -d orders --section=data --disable-triggers /backup/orders.dump
# 需要 -S 指定超级用户,或以超级用户运行
pg_restore -d orders -S postgres --section=data --disable-triggers /backup/orders.dump--no-data-for-failed-tables 仅在直接连库时有效
生成 SQL 脚本时不生效,因为脚本模式下不知道建表是否会失败。
恢复后必须 ANALYZE
不更新统计信息会让恢复后的查询计划严重劣化,某些场景下性能下降一个数量级:
ANALYZE;序列值不会自动跟随数据修正
归档中的 SEQUENCE SET 是备份时刻的值。若在「备份 → 恢复」之间又有数据写入并产生了更大的 ID,恢复后可能发生主键冲突。恢复后应校验:
SELECT last_value FROM orders_id_seq;
SELECT max(id) FROM orders;恢复脚本会执行源端超级用户写入的任意代码
这是官方的明确安全警告。不可信归档必须先用 -f 转成文本审阅。
最佳实践
- 默认不用
--single-transaction,改用「恢复到临时库 + 校验 + 切换」获得原子性,从而保留-j并行能力。
createdb orders_new && pg_restore -d orders_new -j 8 /backup/orders.dump并行度从服务器 CPU 核数起步,再用真实数据压测调整。核数只是一个安全的起点,过高会因资源争抢反而变慢。
跨环境恢复一律加
--no-owner --no-privileges,消除「角色不存在」这类环境相关的报错噪音,让真正的错误显形。单表恢复用
-L清单,不要用-t,否则索引与约束会被漏掉,恢复出来的表「看起来对、用起来慢」。
pg_restore -l /backup/orders.dump > /tmp/toc.txt
pg_restore -L /tmp/toc.txt -d orders /backup/orders.dump- 恢复前先校验归档可读。这是最廉价的前置检查,能挡掉「备份文件本身就是坏的」这类最糟糕的情况:
pg_restore -l "$DUMP" > /dev/null || { echo "corrupt"; exit 1; }把恢复日志留档并按错误类型归类,区分「环境问题」与「数据问题」。加
-v得到详细进度,便于定位卡点。恢复后立即执行
ANALYZE,这是恢复流程的必备步骤而不是可选项。恢复后校验关键不变量:表行数、序列当前值、约束是否齐全、索引是否建立。
SELECT count(*) FROM orders;
SELECT last_value, is_called FROM orders_id_seq;psql -d orders -c '\d orders'大库恢复优先用
directory格式归档,它同时支持并行导出与并行恢复,也便于逐文件处理与增量传输。恢复耗时纳入演练指标。定期测量「从归档恢复到可用状态」的总时长,验证它是否满足恢复时间目标;RTO 超标时应转向物理备份方案。
不可信归档先转文本审阅再执行,把「恢复即执行任意代码」这一风险显式管控起来。
pg_restore -f /tmp/review.sql "$DUMP" && less /tmp/review.sql- 生产恢复一律在临时库进行,验证通过后再切换。避免
--clean直接作用于生产库造成不可逆的窗口期。
下一节
继续学习:自定义与目录格式