部分备份(表 / 模式过滤)
完整的逻辑备份会导出整个数据库,但在真实场景里,我们常常只想要其中一部分:给数据分析团队一份 tenant_a 模式的快照、把付费数据同步到测试库、或者在一张几百 GB 的日志表上「只要结构不要数据」。这种「只导出数据库的一部分对象」的需求,就是部分备份(partial dump)。
pg_dump 为此提供了两层控制手段。第一层是命令行选择开关:-t / -T 管表、-n / -N 管模式、--exclude-table-data 管「只要结构不要数据」。第二层是 PostgreSQL 17 引入的 --filter 过滤文件:把 include / exclude 规则写进一个文本文件,让复杂的过滤条件可维护、可复用、可纳入版本控制。
理解这两层手段的匹配规则与边界非常重要。部分备份不是「免费缩小版的全库备份」——过滤会把数据库的对象依赖(分区、序列、外键、扩展)切开,导出可以成功,恢复却可能失败。本文的重点,就是把这套过滤机制讲清楚,并把常见的坑提前标出来。
前置知识
建议先阅读:自定义与目录格式、pg_dump 基础用法
基础概念
什么是部分备份
部分备份指的是:在一次 pg_dump 调用中,通过过滤条件只导出数据库的一部分对象(若干张表、若干模式,或某些表的定义但不含数据)。
它区别于「全库备份后再裁剪」:过滤发生在导出阶段,被排除的对象根本不会写进归档文件,因此归档体积更小、导出更快、也不把敏感数据带到目标环境。
# 全库备份
pg_dump -Fc -f all.dump mydb
# 部分备份:只导出 tenant_a 模式
pg_dump -Fc -n tenant_a -f tenant_a.dump mydb「部分」的三个维度
部分备份可以在三个维度上做取舍,理解它们的区别能帮助你在写过滤规则时不混淆:
| 维度 | 作用对象 | 主要开关 | 典型用途 |
|---|---|---|---|
| 表 | 具体的表 | -t / -T | 只迁移业务主表 |
| 模式 | 命名空间 | -n / -N | 按租户 / 按模块导出 |
| 数据 | 表的内容(不含定义) | --exclude-table-data | 大表只要结构 |
三条轴可以叠加使用:例如「导出 public 模式里所有表,但排除 event_log 的数据」就是「模式维度 + 数据维度」的组合。
过滤器开关 vs 过滤文件
| 特性 | 命令行开关(-t / -n / -T / -N) | --filter 过滤文件(PG17+) |
|---|---|---|
| 引入版本 | 一直存在 | PostgreSQL 17 |
| 可表达的条件数 | 靠重复开关堆叠 | 一行一条,条数不限 |
| 可读性 | 命令行一长串,难维护 | 文件里一行一条,有注释 |
| 版本管理 | 只能藏在脚本里 | 可以提交进 Git,随代码评审 |
| 支持的对象类型 | 表、模式、扩展等少数几类 | 表、表数据、模式、扩展、外部数据等 |
| 能否排除「表数据」 | 用 --exclude-table-data | exclude table_data <pattern> |
一句话选择建议:临时一次性操作就用开关,需要长期维护、需要评审的过滤规则就用过滤文件。
匹配模式(pattern)规则
无论开关还是过滤文件,pattern 的语法都继承自 psql 的对象名匹配规则:
*匹配任意长度的字符串(包括空串);?匹配任意单个字符;- 需要匹配字面量
*或?时,用反斜杠转义(\*、\?); - 模式可以写成
schema.table的形式限定模式; - 不写模式部分时,按当前
search_path/ 默认可见对象来匹配。
# 匹配 public 模式下所有以 log_ 开头的表
pg_dump -Fc -t 'public.log_*' -f logs.dump mydb
# 匹配任意模式下名为 orders 的表
pg_dump -Fc -t 'orders' -f orders.dump mydb模式不是正则
pattern 是 psql 风格的通配(* 与 ?),不是 POSIX 正则。写 ^orders$ 这类正则锚点不会生效,反而会被当成字面量去匹配表名。
依赖会被切开
部分备份最大的风险在于对象依赖被过滤切断。数据库里的对象不是彼此孤立的:
- 表可以有序列(
serial/identity的底层)、外键、触发器、索引; - 表可以继承自父表,或作为分区表的分区;
- 表可能依赖某张表里的自定义类型、某个扩展提供的类型或函数。
pg_dump 在做部分备份时不会自动把「被选中对象所依赖的其他对象」一并导出。官方文档对此有明确提醒:无法保证一张表的单独 dump 能独立恢复到干净的数据库中。
部分备份必须验证可恢复性
只导出 orders 表,如果它有一个 orders_customer_fk 外键指向 customers,那么单独恢复这张表时,外键的创建会失败(找不到 customers)。任何部分备份都必须在干净环境里实际恢复验证过一次,才能算「可用」。
语法与用法
选择类开关(pg_dump)
-t pattern, --table=pattern 只导出匹配的表(可重复)
-n pattern, --schema=pattern 只导出匹配的模式(可重复)
-N pattern, --exclude-schema=pattern 排除匹配的模式(可重复)
-T pattern, --exclude-table=pattern 排除匹配的表(可重复)
-e pattern, --extension=pattern 只导出匹配的扩展(可重复)
--exclude-table-data=pattern 导出匹配表的结构,但不导出数据(可重复)
--strict-names 要求每个 -e / -n / -t 模式至少命中一个对象恢复类开关(pg_restore)
-t pattern, --table=pattern 只恢复匹配的表
-n pattern, --schema=pattern 只恢复匹配的模式
-N pattern, --exclude-schema=pattern 排除匹配的模式
-I index, --index=index 只恢复指定的索引
-P function, --function=function 只恢复指定的函数
-T trigger, --trigger=trigger 只恢复指定的触发器
-l, --list 打印归档清单(TOC)
-L list-file, --use-list=list-file 按编辑过的清单文件选择性恢复过滤文件语法(PG17+)
<command> <object-type> <pattern>command取值只有两个:include、exclude;object-type是关键字(见「详细说明」中的白名单表);pattern与开关里的写法一致;- 以
#开头的行是注释,空行会被忽略; pattern可以用引号包起来,允许跨行;- 文件名传
-表示从标准输入读取。
详细说明
表级选择:-t / --table
-t 是部分备份里最常用的开关。它可以重复出现,多个 -t 之间是「或」的关系:
# 导出三张表
pg_dump -Fc \
-t public.orders \
-t public.order_items \
-t public.customers \
-f orders_subset.dump mydb它的语义要点:
- 只导出匹配的表本身,以及从属于这些表的附属对象(索引、触发器、规则、约束、
RULE)。其他非表对象(函数、视图、类型、扩展)不会被导出。 - 匹配按条目名进行。如果同一个表名出现在多个模式中,且模式未限定,可能命中多张表。
-t与-n/-N的目标不同:-n/-N控制的是「除表以外的其他模式内对象」,而-t已经把导出范围限定为表及其附属对象,因此两者同时使用时,-n/-N对表的选择没有影响。
序列不会自动跟着走
serial / identity 列的底层序列是一个独立对象(TOC 中的 SEQUENCE 与 SEQUENCE SET 条目),它的名字通常与表名不同。用 -t 精确选中表时,序列条目可能不在选择范围内。恢复后请务必检查序列当前值:
SELECT last_value, is_called FROM orders_id_seq;若为空或从 1 开始,需要按业务现状手工 setval() 修正,否则新插入的行可能与历史数据主键冲突。
表级排除:-T / --exclude-table
-T 是 -t 的反面:导出除匹配表之外的所有内容。它常用于「整库搬迁,但某几张巨大的日志表不带数据」这类需求。
# 整库导出,但完全不要 event_log 这张表
pg_dump -Fc -T public.event_log -f mydb.dump mydb几点要注意:
-T排除的是整张表:定义和数据都不要。如果只想去掉数据,用下面介绍的--exclude-table-data。-T可以与-n组合,例如「导出public模式,但排除public.tmp_*」。- 如果
-T的模式没有命中任何表,pg_dump默认静默通过;想让它在没命中时报错,配合--strict-names。
只排除数据:--exclude-table-data
这个开关专门解决「要结构,不要数据」的诉求,注意它没有单字母短选项:
# 整库结构 + 除了 audit_log 之外的所有数据
pg_dump -Fc --exclude-table-data='public.audit_log' -f mydb.dump mydb它和被排除的表的处理方式差别如下:
| 方式 | 表定义 | 表数据 | 后续能恢复表结构吗 |
|---|---|---|---|
-T | 不导出 | 不导出 | 否,表根本不存在 |
--exclude-table-data | 导出 | 不导出 | 是,得到一张空表 |
| 默认 | 导出 | 导出 | 是,且带数据 |
对于「先把生产结构搬到测试库、数据自己造」的典型场景,--exclude-table-data 是首选;如果一张巨大的日志表连结构都不需要,用 -T 更彻底。
也可以反向做「只要数据」
如果诉求是「只导出某张表的数据、不要定义」,用 -a 配合 -t:
pg_dump -a -t public.orders -f orders_data.sql mydb模式级选择与排除:-n / -N
-n(选择)与 -N(排除)作用于模式(schema)这一层。多租户系统里每个租户一个模式时,-n 是最自然的切分方式:
# 只导出 tenant_a 模式下的全部对象
pg_dump -Fc -n tenant_a -f tenant_a.dump mydb
# 导出除了 staging 模式之外的所有内容
pg_dump -Fc -N staging -f prod_only.dump mydb与 -n 相关的两个易错点:
-n public不会自动包含pg_catalog之外的「依赖模式」。如果tenant_a里的表使用了位于shared模式下的自定义类型,该类型不会被导出,恢复时会报type "shared.money" does not exist。-n与-t同时给出时,语义是「这些模式中的、且匹配-t的表」,而不是「这些模式里的所有对象,外加匹配-t的表」。写过滤规则时要避免这种含糊的组合。
# 典型依赖陷阱示意:类型在另一个模式里
pg_dump -Fc -n tenant_a -f tenant_a.dump mydb
# 恢复时可能报:type "shared.money" does not exist模式过滤不解决跨模式依赖
跨模式的类型、函数、扩展依赖是逻辑备份的固有边界。最稳妥的做法是:要么把整个数据库导出去掉不想要的部分(用 -N),要么显式把所有被依赖的对象一起导出。
--strict-names 严格校验
默认情况下,-t / -n / -e 的模式如果没有命中任何对象,pg_dump 只会给一句提示(甚至不提示),然后继续执行——这在脚本里非常危险:一个拼写错误会让你的「部分备份」变成「空备份」,而脚本依然返回成功。
--strict-names 让每个模式至少命中一个对象,否则直接报错退出:
# 若 tenant_a 不存在,命令会失败而不是产出空文件
pg_dump -Fc --strict-names -n tenant_a -f tenant_a.dump mydb它同时适用于 pg_dump 与 pg_restore(在 pg_restore 中作用于 -n / -t 等模式)。
建议默认打开
在自动化备份脚本里,凡是使用了 -t / -n / -e 的地方,都建议加上 --strict-names。它能挡掉「表被改名 / 模式被下线 / 模式写错」引发的静默空备份。
--filter 过滤文件(PG17+)
PostgreSQL 17 为 pg_dump、pg_dumpall、pg_restore 引入了 --filter=FILENAME:把 include / exclude 规则从命令行搬进一个文件。
pg_dump -Fc --filter=/backup/mydb.filter -f mydb.dump mydb文件里一行一条规则,格式为 <command> <object-type> <pattern>:
# /backup/mydb.filter
# 以 # 开头的是注释,空行会被忽略
# 只导出这两个模式
include schema public
include schema tenant_a
# 连同分区/继承子表一起导出
include table_and_children public.orders
# 大表只要结构,不要数据
exclude table_data public.audit_log
exclude table_data public.event_log规则语义需要说清楚:
- include 与 exclude 并存时,先按 include 圈定范围,再按 exclude 从中剔除;只写 exclude 时,等价于「全都要,除了……」。因此「只要排除大表数据」可以只写 exclude。
- 规则顺序不是「后来居上」的覆盖关系,不要指望用一条
include去「撤销」前面的exclude。 - 文件名传
-表示从标准输入读取,便于在管道里动态生成规则。
# 从标准输入读取过滤规则
printf 'exclude table_data public.audit_log\n' | pg_dump -Fc --filter=- -f mydb.dump mydb为什么值得用文件
当过滤条件超过三五条,命令行会变得难以阅读与维护。放进文件后:可以写注释说明「为什么排除这张表」、可以提交进 Git 做评审、可以被多个脚本复用、出问题时 diff 一下就知道谁改了什么。
过滤文件的 object-type 白名单
--filter 里的 object-type 是关键字,不是任意字符串。pg_dump 对 include 与 exclude 各自只接受一组固定的关键字,写错会直接报 ... is not allowed 并退出。
| object-type | 用于 include | 用于 exclude | 含义 |
|---|---|---|---|
table | ✔ | ✔ | 表本身 |
table_and_children | ✔ | ✔ | 表及其分区 / 继承子表 |
table_data | ✗ | ✔ | 表的数据 |
table_data_and_children | ✗ | ✔ | 表及其子表的数据 |
schema | ✔ | ✔ | 模式 |
extension | ✔ | ✔ | 扩展 |
foreign_data | ✔ | ✔ | 外部数据(--include-foreign-data 相关) |
从这张表能读出两个关键结论:
table_data只能出现在exclude里。想「只要某几张表的数据」不能靠include table_data,正确做法是-a -t <表名>(数据模式 + 表选择)。- 通配与「连同子表」是分开的关键字。要连分区子表一起带走,必须写
table_and_children/table_data_and_children,普通的table只命中表本身。
常见笔误:写成「两步」
不存在 include table data <pattern> 这种「命令 + 两个词」的写法。table_data 是一个关键字,且只允许出现在 exclude 位置。写成两个词会被解析成未知的 object-type,命令直接失败。
pg_dumpall 的 --filter 用途很窄——它面向整个集群,过滤的对象是数据库,主要用于「排除某些库不导出」:
# /backup/cluster.filter
exclude database template1
exclude database staging_scratchpg_restore 也支持 --filter,且它的白名单比 pg_dump 更宽,除表 / 模式类之外还可以针对函数、索引、触发器等条目做过滤——这正好对应 pg_restore 的 -P / -I / -T 三个开关。
分区表与继承子表:*_and_children
PostgreSQL 10 引入声明式分区后,一张逻辑上的表其实由「父表 + 多个分区子表」组成。这个结构对部分备份影响很大:
- 只写
include table public.orders,可能只导出了父表定义,分区子表(如orders_2026_09)不在范围内; - 数据实际存放在子表里,父表本身通常是空的,于是「导出了 orders 表却没有任何数据」。
正确写法是用带 children 的关键字:
# 连同所有分区子表一起导出(定义 + 数据)
include table_and_children public.orders# 命令行等价的近似做法:父表 + 按命名规律匹配分区
pg_dump -Fc -t 'public.orders' -t 'public.orders_*' -f orders.dump mydb对于「只想排除某张分区表的数据」的场景:
exclude table_data_and_children public.audit_log分区表的备份粒度
分区表的「表」在物理上是一组表。做部分备份前,先用 \d+ 或查询 pg_class / pg_inherits 确认父子关系,避免出现「备份成功、恢复后数据为零」的假象。
定义与数据分离:table_data
table_data 的作用是只针对数据做增删,不动表的定义。典型用法是「全库备份,但几张超大日志表只要结构」:
# /backup/mydb.filter
exclude table_data public.audit_log
exclude table_data public.event_stream它和 --exclude-table-data 是同一件事的两种写法,选哪个取决于你已经在用哪种风格:
| 写法 | 表达方式 | 适合场景 |
|---|---|---|
--exclude-table-data=pattern | 命令行开关 | 一两条规则,临时执行 |
exclude table_data pattern | 过滤文件 | 规则较多,需要长期维护 |
需要强调:被排除数据只是「不导出数据」,表定义仍然在归档里。恢复出来是一张空表,索引、约束、触发器都在,这对「先建结构、后灌数据」的流程非常合适。
恢复阶段的过滤
过滤不止发生在导出阶段。pg_restore 提供了基于归档 TOC 的恢复期选择性恢复,这是归档格式相对 plain 格式的核心优势。
基本流程是「先看清单,再改清单,然后按清单恢复」:
# 1) 打印归档清单
pg_restore -l mydb.dump > mydb.list
# 2) 编辑清单:注释掉不想恢复的行(行首加 ;)
# 3) 按编辑后的清单恢复
pg_restore -L mydb.list -d target_db mydb.dump也可以直接用开关挑选,不必编辑清单文件:
# 只恢复 orders 表(以及它的数据条目)
pg_restore -d target_db -t public.orders mydb.dump
# 只恢复 tenant_a 模式
pg_restore -d target_db -n tenant_a mydb.dump
# 只恢复某个索引 / 函数 / 触发器
pg_restore -d target_db -I public.orders_pkey mydb.dump
pg_restore -d target_db -P public.calc_tax mydb.dumppg_restore -t 只匹配表条目
pg_restore -t 是按条目名匹配的,命中的是表的 TABLE / TABLE DATA 条目。该表的索引、约束、触发器等是独立的 TOC 条目,名字与表名不同,因此不会被 -t 一并选中。要连同索引一起恢复,需要额外指定 -I,或改为编辑 -l 清单文件。
过滤与对象依赖的冲突
无论过滤发生在导出还是恢复阶段,只要有选择,就存在「依赖被切断」的可能。下表列出最常见的几类冲突:
| 被选中的对象 | 依赖的对象 | 冲突表现 |
|---|---|---|
| 带外键的表 | 被外键引用的表 | relation "customers" does not exist |
| 使用自定义类型的表 | 类型所属的模式 | type "shared.money" does not exist |
| 分区子表 | 父表定义 | 恢复后无法 ATTACH 到不存在的父表 |
带 serial 的表 | 底层序列 | 序列缺失,主键从 1 重新开始 |
| 使用扩展类型的表 | 扩展(如 postgis) | type "geometry" does not exist |
| 带触发器的表 | 触发器函数 | function ... does not exist |
处理思路只有三条:
- 把依赖一起选中(例如同时
include类型所在的模式、被引用的表、扩展); - 降低耦合(恢复时先建好依赖,或用
--disable-triggers之类手段绕开运行期约束); - 放弃「部分恢复」的幻想,改为先全量恢复再裁剪。
实战示例
示例一:导出单张表(含索引与约束)
pg_dump -Fc --strict-names \
-t public.orders \
-f /backup/orders.dump \
orders_db
# 查看归档里到底有哪些条目
pg_restore -l /backup/orders.dump;
; Archive created at 2026-09-30 10:20:11 CST
; dbname: orders_db
; TOC Entries: 9
; Format: CUSTOM
;
3; 1259 16385 TABLE public orders postgres
4; 1259 16390 SEQUENCE public orders_id_seq postgres
5; 0 0 SEQUENCE SET public orders_id_seq postgres
6; 2606 16392 CONSTRAINT public orders_pkey postgres
7; 1259 16397 INDEX public orders_created_at_idx postgres
8; 2606 16401 CONSTRAINT public orders_customer_fk postgres注意清单里 orders_customer_fk 这条外键也在归档里。如果目标库没有 customers 表,恢复这一步会失败。
示例二:按模式导出多租户数据
# 只导出两个租户模式,模式写错就报错
pg_dump -Fc --strict-names \
-n tenant_a \
-n tenant_b \
-f /backup/tenants.dump \
saas_db如果租户表还依赖一个共享模式(存放自定义类型或公共函数),必须把它一起带上:
pg_dump -Fc --strict-names \
-n shared \
-n tenant_a \
-n tenant_b \
-f /backup/tenants.dump \
saas_db示例三:整库备份但排除大表数据
pg_dump -Fc \
--exclude-table-data='public.audit_log' \
--exclude-table-data='public.event_stream' \
-f /backup/mydb.dump \
mydb# 验证:归档应显著变小
ls -lh /backup/mydb.dump-rw-r--r-- 1 postgres postgres 118M Sep 30 10:25 /backup/mydb.dump恢复后这两张表存在但为空,结构、索引、约束完整。
示例四:使用过滤文件组合多条规则
# /backup/saas.filter
# 导出公共模式与两个租户模式
include schema public
include schema tenant_a
include schema tenant_b
# 订单表连同分区子表一起带
include table_and_children public.orders
# 审计与事件表只要结构
exclude table_data public.audit_log
exclude table_data public.event_stream
# 排除临时表
exclude table 'public.tmp_*'pg_dump -Fc --filter=/backup/saas.filter -f /backup/saas.dump saas_db
# 确认过滤效果
pg_restore -l /backup/saas.dump | grep -c 'TABLE DATA'示例五:恢复时只挑一张表
# 从全库归档里,只把 orders 表恢复进一个新库
createdb orders_only
pg_restore -d orders_only \
-t public.orders \
/backup/mydb.dump如果该表的索引与约束也需要,先打印清单再编辑:
pg_restore -l /backup/mydb.dump > /tmp/mydb.list
# 编辑 /tmp/mydb.list,只保留 orders 相关的条目
# 例如用 grep 生成一个精简清单
grep -E 'TABLE public orders|TABLE DATA public orders|orders_pkey|orders_customer_fk' \
/tmp/mydb.list > /tmp/orders.list
pg_restore -d orders_only -L /tmp/orders.list /backup/mydb.dump示例六:为测试环境准备「去数据」的快照
# /backup/test.filter
# 结构全要,业务数据全不要(只留字典表)
exclude table_data public.orders
exclude table_data public.order_items
exclude table_data public.customers
exclude table_data public.paymentspg_dump -Fc --filter=/backup/test.filter -f /backup/empty_schema.dump prod_db
# 恢复后手工灌入脱敏数据
createdb test_db
pg_restore -d test_db /backup/empty_schema.dump
psql -d test_db -c "SELECT count(*) FROM orders;" count
-------
0
(1 row)这才是「给测试环境一份干净结构」的正确姿势——比 TRUNCATE 生产库安全得多。
注意事项
过滤不等于脱敏。 部分备份只是「不导出某些对象」,被选中的表依然是原始数据。要用生产数据做测试,必须另外做脱敏处理,不能指望 -t 帮你过滤掉敏感字段。
--strict-names 要当成默认选项。 模式拼错时 pg_dump 默认静默通过,脚本返回码依然是 0,自动化流程里会悄悄产出空备份。凡是用了 -t / -n / -e 的地方都建议加上它。
-t 与 --exclude-table-data 的差别要想清楚。 前者让表彻底消失,后者只是让表变空。选错会导致「目标库缺表」或「目标库有表但没数据」两类不同的事故。
分区表必须显式带上子表。 父表通常不存数据,只 include table 父表会得到一个「表在、数据空」的归档。用 table_and_children 或按分区命名规律匹配。
序列值不会自动跟随。 serial / identity 的底层序列是独立对象,部分备份后要检查序列当前值,必要时用 setval() 修正,避免主键冲突。
归档版本要与恢复端匹配。 pg_restore 无法读取比自己更新版本的归档;pg_dump 也不认识更新版本的归档。跨版本迁移时用低版本工具导出、高版本恢复,或统一为 plain 格式。
部分恢复时目标库最好为空。 对已有数据的库做选择性恢复,容易因对象已存在而报错。此时配合 --clean --if-exists 或先清理目标对象。
过滤规则要写进版本管理。 散落在 shell 脚本里的 -t、-T 迟早会失控。把规则收敛到 --filter 文件里,随代码一起评审和回溯。
最佳实践
- 用「导出 → 干净库验证恢复」的闭环来验收部分备份。 任何部分备份在正式采用前,都要在一个临时干净库里跑一遍
pg_restore,把relation does not exist、type does not exist这类依赖错误在离线环境里暴露出来:
createdb verify_tmp
pg_restore -d verify_tmp --exit-on-error /backup/subset.dump
dropdb verify_tmp- 给所有模式类开关加上
--strict-names。 让拼写错误在导出阶段就失败,而不是在恢复阶段才发现「备份是空的」:
pg_dump -Fc --strict-names -n tenant_a -f /backup/tenant_a.dump saas_db- 规则超过三条就改用
--filter过滤文件。 把过滤条件从命令行搬进文件,附带注释说明每条例外的业务原因,并提交进 Git:
# /backup/saas.filter
include schema tenant_a
exclude table_data public.audit_log # 单表 400GB,测试不需要- 分区表一律使用
table_and_children。 避免「父表在、数据不在」的假备份;导出后检查归档里是否有子表条目:
pg_restore -l /backup/orders.dump | grep -c 'TABLE DATA'只排除数据的需求,优先用
--exclude-table-data。 它比「整表排除 + 事后手工建表」可靠得多,恢复出来的空表结构完整(索引、约束、触发器都在)。把
pg_restore -l的输出纳入日常核查。 归档清单一目了然地告诉你「这次到底导了什么」,是排查部分备份问题最快的手段:
pg_restore -l /backup/subset.dump | head -n 30为部分备份单独规划目标库,避免与全量备份混淆。 部分归档只能恢复到干净库(或经过清理的库),不要试图把它叠加到已有生产库上。
跨模式依赖要显式纳入规则。 自定义类型、公共函数、扩展所在模式,必须在过滤规则里明确
include,否则恢复必然失败。序列值纳入恢复后的核对清单。 恢复部分数据后,逐张表检查序列,必要时修正:
SELECT last_value, is_called FROM orders_id_seq;
SELECT max(id) FROM orders;不要用部分备份替代全量备份。 部分备份是开展特定任务的工具(迁移、测试、按租户交付),不能作为灾难恢复的唯一依托。生产库始终需要完整备份 + WAL 归档。
在恢复阶段优先用
-L清单文件而不是大量开关。 清单文件能清晰记录「这次恢复了哪些条目」,且可以反复复用,比一长串-t/-I更可控:
pg_restore -L /backup/orders.list -d orders_only /backup/mydb.dump- 为过滤规则写测试。 至少做到「规则变更后自动跑一次导出 + 恢复验证」,让过滤规则的修改也能被 CI 拦住,而不是等到上线恢复时才发现表没了。
下一节
继续学习:物理备份原理