Skip to content

部分备份(表 / 模式过滤) ​

完整的逻辑备份会导出整个数据库,但在真实场景里,我们常常只想要其中一部分:给数据分析团队一份 tenant_a 模式的快照、把付费数据同步到测试库、或者在一张几百 GB 的日志表上「只要结构不要数据」。这种「只导出数据库的一部分对象」的需求,就是部分备份(partial dump)。

pg_dump 为此提供了两层控制手段。第一层是命令行选择开关:-t / -T 管表、-n / -N 管模式、--exclude-table-data 管「只要结构不要数据」。第二层是 PostgreSQL 17 引入的 --filter 过滤文件:把 include / exclude 规则写进一个文本文件,让复杂的过滤条件可维护、可复用、可纳入版本控制。

理解这两层手段的匹配规则与边界非常重要。部分备份不是「免费缩小版的全库备份」——过滤会把数据库的对象依赖(分区、序列、外键、扩展)切开,导出可以成功,恢复却可能失败。本文的重点,就是把这套过滤机制讲清楚,并把常见的坑提前标出来。

前置知识

建议先阅读:自定义与目录格式、pg_dump 基础用法

基础概念 ​

什么是部分备份 ​

部分备份指的是:在一次 pg_dump 调用中,通过过滤条件只导出数据库的一部分对象(若干张表、若干模式,或某些表的定义但不含数据)。

它区别于「全库备份后再裁剪」:过滤发生在导出阶段,被排除的对象根本不会写进归档文件,因此归档体积更小、导出更快、也不把敏感数据带到目标环境。

bash
# 全库备份
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-dataexclude table_data <pattern>

一句话选择建议:临时一次性操作就用开关,需要长期维护、需要评审的过滤规则就用过滤文件。

匹配模式(pattern)规则 ​

无论开关还是过滤文件,pattern 的语法都继承自 psql 的对象名匹配规则:

  • * 匹配任意长度的字符串(包括空串);
  • ? 匹配任意单个字符;
  • 需要匹配字面量 * 或 ? 时,用反斜杠转义(\*、\?);
  • 模式可以写成 schema.table 的形式限定模式;
  • 不写模式部分时,按当前 search_path / 默认可见对象来匹配。
bash
# 匹配 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) ​

text
-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) ​

text
-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+) ​

text
<command> <object-type> <pattern>
  • command 取值只有两个:include、exclude;
  • object-type 是关键字(见「详细说明」中的白名单表);
  • pattern 与开关里的写法一致;
  • 以 # 开头的行是注释,空行会被忽略;
  • pattern 可以用引号包起来,允许跨行;
  • 文件名传 - 表示从标准输入读取。

详细说明 ​

表级选择:-t / --table ​

-t 是部分备份里最常用的开关。它可以重复出现,多个 -t 之间是「或」的关系:

bash
# 导出三张表
pg_dump -Fc \
  -t public.orders \
  -t public.order_items \
  -t public.customers \
  -f orders_subset.dump mydb

它的语义要点:

  1. 只导出匹配的表本身,以及从属于这些表的附属对象(索引、触发器、规则、约束、RULE)。其他非表对象(函数、视图、类型、扩展)不会被导出。
  2. 匹配按条目名进行。如果同一个表名出现在多个模式中,且模式未限定,可能命中多张表。
  3. -t 与 -n / -N 的目标不同:-n / -N 控制的是「除表以外的其他模式内对象」,而 -t 已经把导出范围限定为表及其附属对象,因此两者同时使用时,-n / -N 对表的选择没有影响。

序列不会自动跟着走

serial / identity 列的底层序列是一个独立对象(TOC 中的 SEQUENCE 与 SEQUENCE SET 条目),它的名字通常与表名不同。用 -t 精确选中表时,序列条目可能不在选择范围内。恢复后请务必检查序列当前值:

sql
SELECT last_value, is_called FROM orders_id_seq;

若为空或从 1 开始,需要按业务现状手工 setval() 修正,否则新插入的行可能与历史数据主键冲突。

表级排除:-T / --exclude-table ​

-T 是 -t 的反面:导出除匹配表之外的所有内容。它常用于「整库搬迁,但某几张巨大的日志表不带数据」这类需求。

bash
# 整库导出,但完全不要 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 ​

这个开关专门解决「要结构,不要数据」的诉求,注意它没有单字母短选项:

bash
# 整库结构 + 除了 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:

bash
pg_dump -a -t public.orders -f orders_data.sql mydb

模式级选择与排除:-n / -N ​

-n(选择)与 -N(排除)作用于模式(schema)这一层。多租户系统里每个租户一个模式时,-n 是最自然的切分方式:

bash
# 只导出 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 相关的两个易错点:

  1. -n public 不会自动包含 pg_catalog 之外的「依赖模式」。如果 tenant_a 里的表使用了位于 shared 模式下的自定义类型,该类型不会被导出,恢复时会报 type "shared.money" does not exist。
  2. -n 与 -t 同时给出时,语义是「这些模式中的、且匹配 -t 的表」,而不是「这些模式里的所有对象,外加匹配 -t 的表」。写过滤规则时要避免这种含糊的组合。
bash
# 典型依赖陷阱示意:类型在另一个模式里
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 让每个模式至少命中一个对象,否则直接报错退出:

bash
# 若 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 规则从命令行搬进一个文件。

bash
pg_dump -Fc --filter=/backup/mydb.filter -f mydb.dump mydb

文件里一行一条规则,格式为 <command> <object-type> <pattern>:

text
# /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。
  • 文件名传 - 表示从标准输入读取,便于在管道里动态生成规则。
bash
# 从标准输入读取过滤规则
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 相关)

从这张表能读出两个关键结论:

  1. table_data 只能出现在 exclude 里。想「只要某几张表的数据」不能靠 include table_data,正确做法是 -a -t <表名>(数据模式 + 表选择)。
  2. 通配与「连同子表」是分开的关键字。要连分区子表一起带走,必须写 table_and_children / table_data_and_children,普通的 table 只命中表本身。

常见笔误:写成「两步」

不存在 include table data <pattern> 这种「命令 + 两个词」的写法。table_data 是一个关键字,且只允许出现在 exclude 位置。写成两个词会被解析成未知的 object-type,命令直接失败。

pg_dumpall 的 --filter 用途很窄——它面向整个集群,过滤的对象是数据库,主要用于「排除某些库不导出」:

text
# /backup/cluster.filter
exclude database template1
exclude database staging_scratch

pg_restore 也支持 --filter,且它的白名单比 pg_dump 更宽,除表 / 模式类之外还可以针对函数、索引、触发器等条目做过滤——这正好对应 pg_restore 的 -P / -I / -T 三个开关。

分区表与继承子表:*_and_children ​

PostgreSQL 10 引入声明式分区后,一张逻辑上的表其实由「父表 + 多个分区子表」组成。这个结构对部分备份影响很大:

  • 只写 include table public.orders,可能只导出了父表定义,分区子表(如 orders_2026_09)不在范围内;
  • 数据实际存放在子表里,父表本身通常是空的,于是「导出了 orders 表却没有任何数据」。

正确写法是用带 children 的关键字:

text
# 连同所有分区子表一起导出(定义 + 数据)
include table_and_children public.orders
bash
# 命令行等价的近似做法:父表 + 按命名规律匹配分区
pg_dump -Fc -t 'public.orders' -t 'public.orders_*' -f orders.dump mydb

对于「只想排除某张分区表的数据」的场景:

text
exclude table_data_and_children public.audit_log

分区表的备份粒度

分区表的「表」在物理上是一组表。做部分备份前,先用 \d+ 或查询 pg_class / pg_inherits 确认父子关系,避免出现「备份成功、恢复后数据为零」的假象。

定义与数据分离:table_data ​

table_data 的作用是只针对数据做增删,不动表的定义。典型用法是「全库备份,但几张超大日志表只要结构」:

text
# /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 格式的核心优势。

基本流程是「先看清单,再改清单,然后按清单恢复」:

bash
# 1) 打印归档清单
pg_restore -l mydb.dump > mydb.list

# 2) 编辑清单:注释掉不想恢复的行(行首加 ;)

# 3) 按编辑后的清单恢复
pg_restore -L mydb.list -d target_db mydb.dump

也可以直接用开关挑选,不必编辑清单文件:

bash
# 只恢复 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.dump

pg_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

处理思路只有三条:

  1. 把依赖一起选中(例如同时 include 类型所在的模式、被引用的表、扩展);
  2. 降低耦合(恢复时先建好依赖,或用 --disable-triggers 之类手段绕开运行期约束);
  3. 放弃「部分恢复」的幻想,改为先全量恢复再裁剪。

实战示例 ​

示例一:导出单张表(含索引与约束) ​

bash
pg_dump -Fc --strict-names \
  -t public.orders \
  -f /backup/orders.dump \
  orders_db

# 查看归档里到底有哪些条目
pg_restore -l /backup/orders.dump
text
;
; 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 表,恢复这一步会失败。

示例二:按模式导出多租户数据 ​

bash
# 只导出两个租户模式,模式写错就报错
pg_dump -Fc --strict-names \
  -n tenant_a \
  -n tenant_b \
  -f /backup/tenants.dump \
  saas_db

如果租户表还依赖一个共享模式(存放自定义类型或公共函数),必须把它一起带上:

bash
pg_dump -Fc --strict-names \
  -n shared \
  -n tenant_a \
  -n tenant_b \
  -f /backup/tenants.dump \
  saas_db

示例三:整库备份但排除大表数据 ​

bash
pg_dump -Fc \
  --exclude-table-data='public.audit_log' \
  --exclude-table-data='public.event_stream' \
  -f /backup/mydb.dump \
  mydb
bash
# 验证:归档应显著变小
ls -lh /backup/mydb.dump
text
-rw-r--r--  1 postgres postgres  118M Sep 30 10:25 /backup/mydb.dump

恢复后这两张表存在但为空,结构、索引、约束完整。

示例四:使用过滤文件组合多条规则 ​

text
# /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_*'
bash
pg_dump -Fc --filter=/backup/saas.filter -f /backup/saas.dump saas_db

# 确认过滤效果
pg_restore -l /backup/saas.dump | grep -c 'TABLE DATA'

示例五:恢复时只挑一张表 ​

bash
# 从全库归档里,只把 orders 表恢复进一个新库
createdb orders_only

pg_restore -d orders_only \
  -t public.orders \
  /backup/mydb.dump

如果该表的索引与约束也需要,先打印清单再编辑:

bash
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

示例六:为测试环境准备「去数据」的快照 ​

text
# /backup/test.filter
# 结构全要,业务数据全不要(只留字典表)
exclude table_data public.orders
exclude table_data public.order_items
exclude table_data public.customers
exclude table_data public.payments
bash
pg_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;"
text
 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 文件里,随代码一起评审和回溯。

最佳实践 ​

  1. 用「导出 → 干净库验证恢复」的闭环来验收部分备份。 任何部分备份在正式采用前,都要在一个临时干净库里跑一遍 pg_restore,把 relation does not exist、type does not exist 这类依赖错误在离线环境里暴露出来:
bash
createdb verify_tmp
pg_restore -d verify_tmp --exit-on-error /backup/subset.dump
dropdb verify_tmp
  1. 给所有模式类开关加上 --strict-names。 让拼写错误在导出阶段就失败,而不是在恢复阶段才发现「备份是空的」:
bash
pg_dump -Fc --strict-names -n tenant_a -f /backup/tenant_a.dump saas_db
  1. 规则超过三条就改用 --filter 过滤文件。 把过滤条件从命令行搬进文件,附带注释说明每条例外的业务原因,并提交进 Git:
text
# /backup/saas.filter
include schema tenant_a
exclude table_data public.audit_log   # 单表 400GB,测试不需要
  1. 分区表一律使用 table_and_children。 避免「父表在、数据不在」的假备份;导出后检查归档里是否有子表条目:
bash
pg_restore -l /backup/orders.dump | grep -c 'TABLE DATA'
  1. 只排除数据的需求,优先用 --exclude-table-data。 它比「整表排除 + 事后手工建表」可靠得多,恢复出来的空表结构完整(索引、约束、触发器都在)。

  2. 把 pg_restore -l 的输出纳入日常核查。 归档清单一目了然地告诉你「这次到底导了什么」,是排查部分备份问题最快的手段:

bash
pg_restore -l /backup/subset.dump | head -n 30
  1. 为部分备份单独规划目标库,避免与全量备份混淆。 部分归档只能恢复到干净库(或经过清理的库),不要试图把它叠加到已有生产库上。

  2. 跨模式依赖要显式纳入规则。 自定义类型、公共函数、扩展所在模式,必须在过滤规则里明确 include,否则恢复必然失败。

  3. 序列值纳入恢复后的核对清单。 恢复部分数据后,逐张表检查序列,必要时修正:

sql
SELECT last_value, is_called FROM orders_id_seq;
SELECT max(id) FROM orders;
  1. 不要用部分备份替代全量备份。 部分备份是开展特定任务的工具(迁移、测试、按租户交付),不能作为灾难恢复的唯一依托。生产库始终需要完整备份 + WAL 归档。

  2. 在恢复阶段优先用 -L 清单文件而不是大量开关。 清单文件能清晰记录「这次恢复了哪些条目」,且可以反复复用,比一长串 -t / -I 更可控:

bash
pg_restore -L /backup/orders.list -d orders_only /backup/mydb.dump
  1. 为过滤规则写测试。 至少做到「规则变更后自动跑一次导出 + 恢复验证」,让过滤规则的修改也能被 CI 拦住,而不是等到上线恢复时才发现表没了。

下一节

继续学习:物理备份原理

参考链接 ​