第 22 章 备份与恢复
与任何包含有价值数据的事物一样,PostgreSQL 数据库也应定期备份。虽然这个过程基本上很简单,但理解其底层技术和前提假设的基本概念非常重要。
备份PostgreSQL数据有两种根本不同的方法:
SQL 转储
文件系统级别的备份
22.1. SQL 转储 #
SQL 转储方法的思路是生成一个包含 SQL 命令的文本文件,当把这些命令送回服务器时,服务器会把数据库重建为转储时的状态。PostgreSQL为此提供了工具程序 pg_dump。该命令的基本用法是:
pg_dumpdbname>outfile
如你所见,pg_dump把结果写到标准输出。我们将在下面看到这样做的用处。
pg_dump是一个常规的PostgreSQL 客户端应用(尽管是一个特别聪明的应用)。这意味着你可以从任何能访问数据库的远程主机上执行这个备份过程。但请记住, pg_dump并不会以特殊的权限运行。特别是,你必须对所有想要备份的表拥有读权限,因此在实践中你几乎总是必须是数据库超级用户。
要指定pg_dump应当连接哪个数据库服务器,可以使用命令行选项-h
和host-p 。默认主机是本地主机,或者由portPGHOST环境变量指定的主机。类似地,默认端口由PGPORT环境变量指示,若未设置,则使用编译时的默认值。(方便的是,服务器通常也有相同的编译时默认值。)
与任何其他PostgreSQL客户端应用一样,
pg_dump默认以与当前操作系统用户名相同的数据库用户名连接。要覆盖这一行为,可以指定-U选项或设置环境变量PGUSER。请记住,pg_dump
的连接同样受常规的客户端认证机制约束(这些机制在第 19 章中描述)。
pg_dump创建的转储在内部是一致的,也就是说,
pg_dump运行期间对数据库的更新不会出现在转储中。
pg_dump工作时不会阻塞数据库上的其他操作。(例外是那些需要以排他锁运行的操作,例如VACUUM FULL。)
重要
当你的数据库模式依赖于 OID(例如用作外键)时,你必须指示
pg_dump把 OID 也一并转储。为此,可以使用
-o命令行选项。“大对象”默认也不会被转储。如果你使用了大对象,请参阅pg_dump的命令参考页。
22.1.1. 恢复转储 #
pg_dump创建的文本文件应由psql 程序读入。恢复转储的一般命令形式是:
psqldbname<infile
其中infile就是你在pg_dump命令中用作outfile
的文件。数据库dbname不会由此命令创建,你必须在执行psql之前自己从template0创建它(例如用createdb -T template0
)。
psql支持与pg_dump类似的用于控制数据库服务器位置和用户名的选项。更多信息见其参考页。
dbname
如果原始数据库中的对象属于不同的用户,那么转储会指示 psql依次以每个受影响的用户连接,然后创建相应的对象。这样便保留了原来的属主关系。然而,这也意味着所有这些用户必须已经存在,而且你必须被允许以每个用户的身份连接。因此,可能有必要临时放宽客户端认证设置。
恢复完成后,在每个数据库上运行ANALYZE是明智的,这样优化器就能获得有用的统计信息。你也可以运行
vacuumdb -a -z来对所有数据库执行ANALYZE。
pg_dump和psql能够写入或读取管道,这使得把一个数据库从一台服务器直接转储到另一台服务器成为可能;例如:
pg_dump -hhost1dbname| psql -hhost2dbname
重要
pg_dump产生的转储是相对于template0
的。这意味着任何添加到template1中的语言、过程等也会被pg_dump转储。因此,恢复时如果你使用了定制的template1,就必须像上面的例子那样从
template0创建空数据库。
提示
通过增大配置参数sort_mem可以提高恢复性能(见第 16.4.2.1 节)。
22.1.2. 使用pg_dumpall #
上述机制在备份整个数据库集群时既繁琐又不合适。为此提供了 pg_dumpall程序。pg_dumpall 备份给定集群中的每个数据库,同时保留集群范围的数据,例如用户和组。pg_dumpall的调用序列很简单:
pg_dumpall > outfile得到的转储可以用psql恢复:
psql template1 < infile
(实际上,你可以指定任何现有的数据库名作为起点,但如果你要在一个空集群中重新装载,那么template1
是唯一可用的选择。)恢复pg_dumpall
转储时总是需要数据库超级用户权限,因为恢复用户和组信息需要这样的权限。
22.1.3. 大型数据库 #
由于PostgreSQL允许表大于系统上的最大文件尺寸,把这样一个表转储到一个文件可能会成问题,因为得到的文件很可能大于系统允许的最大尺寸。由于 pg_dump可以写到标准输出,你可以直接使用标准 Unix 工具来绕过这个潜在问题。
使用压缩转储。. 你可以使用自己喜欢的压缩程序,例如 gzip。
pg_dumpdbname| gzip >filename.gz
恢复时用:
createdbdbnamegunzip -cfilename.gz | psqldbname
或者:
catfilename.gz | gunzip | psqldbname
使用split。. split命令允许你把输出分割成底层文件系统可接受大小的块。例如,要切分为 1 MB 的块:
pg_dumpdbname| split -b 1m -filename
恢复时用:
createdbdbnamecatfilename* | psqldbname
使用定制转储格式。. 如果PostgreSQL是在安装了zlib
压缩库的系统上构建的,定制转储格式会在把数据写入输出文件时压缩数据。对于大型数据库,这会产生与使用gzip
相当的转储尺寸,而且还有一个额外的优点:可以选择性地恢复部分表。下面的命令用定制转储格式转储一个数据库:
pg_dump -Fcdbname>filename
详情见pg_dump和pg_restore的参考页。
22.1.4. 注意事项 #
pg_dump(相应地也包括pg_dumpall)有一些限制,这些限制源于从系统目录中重建某些信息的困难。
具体来说,pg_dump写对象的顺序并不十分精巧。例如,当函数被用作列默认值时,这可能导致问题。唯一的解决办法是手动对转储重新排序。如果你在模式中创建了循环依赖,那么你要做的工作会更多。
出于向后兼容的原因,pg_dump默认不转储大对象。要转储大对象,你必须使用定制输出格式或 TAR 输出格式,并在
pg_dump中使用-b选项。详情见参考页。PostgreSQL源码树的
contrib/pg_dumplo目录中也包含一个可以转储大对象的程序。
请熟悉pg_dump参考页。