PostgreSQL 18 预览: pg_dumpall 的非文本模式

John Doe 四月 21, 2025

你需要快速地导入导出数据吗?现在,PostgreSQL 支持以非文本模式来导出数据了。

沙滩上漫步的大象

特性提交日志

pg_dumpall 的非文本模式及 pg_restore 的相应变化。

pg_dumpall 获得了一个新的-F/--format选项,其含义与 pg_dump 中的相同。默认值是p,表示纯文本格式。对于任何其他值,会创建一个目录,其中包含两个文件:globals.datamap.dat。第一个文件包含用于恢复全局数据的 SQL 语句,第二个文件包含从对象标识符(oid)到数据库名称的映射。它还会包含一个名为databases的子目录,在该子目录中会以指定格式创建归档文件,并使用数据库 oid 命名。

在这些情况下,-f参数是必需的。

如果 pg_restore 遇到包含globals.dat但没有toc.dat的目录,它会先恢复全局设置,然后恢复每个数据库。

pg_restore 获得了两个新选项:-g/--globals-only,用于禁止恢复任何数据库;--exclude-database,用于禁止恢复特定的数据库,其工作方式与 pg_dumpall 中的相同选项一致。

讨论:https://postgr.es/m/cb103623-8ee6-4ba5-a2c9-f32e3a4933fa@dunslane.net

示例

很多 PostgreSQL 用户不喜欢使用 pg_dumpall,原因在于它速度慢,而且无法选择他们想要恢复的内容。这是因为某种程度上,pg_dumpall 只是简单地以纯文本格式顺序运行普通的 pg_dump。

而现在,这一巨大的改进让它变得非常出色。

让我们获取一些对比数据。在该测试实例中有几个数据库:

select datname, pg_size_pretty( pg_database_size(oid) ) from pg_database order by pg_database_size(oid) desc;
     datname     | pg_size_pretty
-----------------+----------------
 redrock_explain | 7325 MB
 redrock         | 238 MB
 pgdoc           | 22 MB
 inst            | 16 MB
 template1       | 7774 kB
 pgdba           | 7694 kB
 template0       | 7694 kB
 postgres        | 7694 kB
(9 rows)

其中一个数据库比其他数据库大得多。使用传统方式运行 pg_dumpall:

$ time pg_dumpall -f pgdump.base.sql

real    0m58.893s
user    0m2.892s
sys     0m28.562s

$ du -h pgdump.base.sql
32G     pgdump.base.sql

$ time gzip -vk pgdump.base.sql
pgdump.base.sql:       88.4% -- created pgdump.base.sql.gz

real    6m31.129s
user    6m8.112s
sys     0m21.083s

$ du -h pgdump.base.sql.gz
3.7G    pgdump.base.sql.gz

所以,将所有数据库转储到单个文件中大约需要一分钟,但文件非常大,达到了 32GB。压缩花费了 6.5 分钟,将文件大小减少到了 3.7GB。

为了完整起见,让我们进行一次传统方式的转储,但采用实时压缩:

$ time pg_dumpall | gzip - > pgdump.compress.pipe.sql.gz

real    6m27.469s
user    6m18.340s
sys     0m31.272s

$ du -h pgdump.compress.pipe.sql.gz
3.7G    pgdump.compress.pipe.sql.gz

和上面的测试进行对比,有了一定的性能提升。

现在,让我们看看还能做些什么:

$ time pg_dumpall -Fc -f pgdump.Fc.dump

real    5m55.864s
user    5m38.110s
sys     0m11.658s

$ du -sh pgdump.Fc.dump
3.7G    pgdump.Fc.dump

使用-Fc选项进行转储,我们又稍微节省了一些时间。

此外,虽然我们无法简单地限制从哪个数据库加载哪些对象,但是可以使用 pg_restore 来加载,并使用它的新选项:

$ pg_restore --globals-only -f globals.sql pgdump.Fc.dump/

这样就可以只恢复全局的元数据(角色、组权限、表空间)。

甚至,我们还可以只恢复部分的数据库。pg_restore 有一个选项--exclude-database=... 。但是,怎么知道转储中都有哪些数据库呢?让我们来看看上面的转储中都有些什么:

$ find pgdump.Fc.dump/ -ls
 94784725       4 drwx------   3 postgres  postgres       4096 Apr 15 11:39 pgdump.Fc.dump/
 94784726       4 -rw-rw-r--   1 postgres  postgres       1751 Apr 15 11:45 pgdump.Fc.dump/global.dat
 94784728       4 -rw-rw-r--   1 postgres  postgres        116 Apr 15 11:45 pgdump.Fc.dump/map.dat
 94784727       4 drwx------   2 postgres  postgres       4096 Apr 15 11:45 pgdump.Fc.dump/databases
 94784747    2348 -rw-rw-r--   1 postgres  postgres    2403266 Apr 15 11:45 pgdump.Fc.dump/databases/574053.dmp
 94784744   24644 -rw-rw-r--   1 postgres  postgres   25233590 Apr 15 11:39 pgdump.Fc.dump/databases/571913.dmp
 94784758     704 -rw-rw-r--   1 postgres  postgres     718709 Apr 15 11:45 pgdump.Fc.dump/databases/571987.dmp
 94784745 3807448 -rw-rw-r--   1 postgres  postgres 3898822633 Apr 15 11:45 pgdump.Fc.dump/databases/16395.dmp
 94784759       4 -rw-rw-r--   1 postgres  postgres       1056 Apr 15 11:45 pgdump.Fc.dump/databases/5.dmp
 94784753       4 -rw-rw-r--   1 postgres  postgres        832 Apr 15 11:45 pgdump.Fc.dump/databases/574187.dmp
 94784742       4 -rw-rw-r--   1 postgres  postgres       1561 Apr 15 11:39 pgdump.Fc.dump/databases/1.dmp

所以,这些文件名也没什么太大帮助。但是,有一个文件还是看起来很有用的:

$ cat pgdump.Fc.dump/map.dat
1 template1
571913 redrock
16395 redrock_explain
574053 inst
574187 pgdba
571987 pgdoc
5 postgres

根据这些名称,我们可以决定只恢复pgdba数据库,通过排除其他数据库来实现:

$ pg_restore -C -f just.one.db.sql --exclude-database="redrock*|template*|inst|pgdoc" pgdump.Fc.dump/

虽然这样可行,但是不能进行反向选择:只恢复一个数据库,或者不恢复全局的元数据。但我认为这些问题是可以解决的。

如果想要恢复单个数据库,我们也可以从databases/目录中恢复其中一个.dmp文件,这些文件都是由pg_dump -Fc产生的普通文件:

$ file pgdump.Fc.dump/databases/574187.dmp
pgdump.Fc.dump/databases/574187.dmp: PostgreSQL custom database dump - v1.16-0

$ pg_restore -l pgdump.Fc.dump/databases/574187.dmp
;
; Archive created at 2025-04-15 11:45:33 CST
;     dbname: pgdba
;     TOC Entries: 4
;     Compression: gzip
;     Dump Version: 1.16-0
;     Format: CUSTOM
...

现在 pg_dumpall 也支持目录格式了,pg_dump 很早就支持这种格式,但是在 pg_dumpall 中,即使使用-Fd选项,我们也无法使用并行处理,因为它没有--jobs选项。在支持并行转储之前,-Fd选项在 pg_dumpall 中可能用处不大。如果你想快速进行转储,对每个数据库使用pg_dump -Fd,并搭配合适的-j N选项,应该会是最好的方法。

非常不错的改进。感谢社区的所有相关人员。

参考

提交日志:https://git.postgresql.org/pg/commitdiff/1495eff7bdb0779cc54ca04f3bd768f647240df2