Postgres pg_dump 每次都以不同的顺序转储数据库

Posted

技术标签:

【中文标题】Postgres pg_dump 每次都以不同的顺序转储数据库【英文标题】:Postgres pg_dump dumps database in a different order every time 【发布时间】:2011-01-11 20:13:54 【问题描述】:

我正在编写一个 php 脚本(它也使用 linux bash 命令),它将通过执行以下操作来运行测试用例:

我正在使用 PostgreSQL 数据库 (8.4.2)...

1.) 创建数据库 2.) 修改数据库 3.) 存储数据库的数据库转储(pg_dump)

4.) 通过执行步骤 1.) 和 2.) 进行回归测试,然后获取另一个数据库转储并将其与步骤 3 中的原始数据库转储进行比较(差异)。)

但是,我发现 pg_dump 并不总是以相同的方式转储数据库。它每次都会以不同的顺序倾倒东西。因此,当我对两个数据库转储进行比较时,比较会导致两个文件不同,而实际上它们是相同的,只是顺序不同。

我可以通过其他方式来执行 pg_dump 吗?

谢谢!

【问题讨论】:

【参考方案1】:

这是一个方便的脚本,用于预处理pg_dump 输出,使其更适合在版本控制中进行差异化和存储:

https://github.com/akaihola/pgtricks

pg_dump_splitsort.py 将转储拆分为以下文件:

0000_prologue.sql: 第一个副本之前的所有内容 0001_<schema>.<table>.sql . .NNNN_<schema>.<table>.sql: 每个表的数据按第一个字段排序 9999_epilogue.sql: 上次 COPY 之后的所有内容

表数据的文件已编号,因此所有文件的简单排序串联可用于重新创建数据库:

$ cat *.sql | psql <database>

我发现快速查看转储之间差异的一个好方法是在整个目录上使用meld 工具:

$ meld old-dump/ new-dump/

在版本控制中存储转储也可以很好地了解差异。以下是如何配置 git 以在差异中使用颜色:

# ~/.gitconfig
[color]
        diff = true
[color "diff"]
        frag = white blue bold
        meta = white green bold
        commit = white red bold

注意:如果您已创建/删除/重命名表,请记住在对新转储进行后处理之前删除所有 .sql 文件。

【讨论】:

【参考方案2】:

这里值得区分模式和数据。模式以相当确定的顺序转储,大多数对象按字母顺序排列,受对象间依赖关系的约束。在一些有限的情况下,顺序没有完全受到限制,并且在外部观察者看来可能是随机的,但这可能会在下一个版本中得到解决。

另一方面,数据按磁盘顺序转储。这通常是您想要的,因为您希望转储速度快,并且不使用大量资源进行排序。您可能会观察到,当您“修改数据库”时,您正在执行更新,这实际上会删除旧值并在末尾附加新值。这当然会扰乱您的差异化策略。

pg_comparator 是一种可能更适合您的工具。

【讨论】:

【参考方案3】:

强制 pg_dump 以任何特定顺序转储数据是不可能的,因为它以磁盘顺序转储数据 - 这种方式要快得多。

您可以对 pg_dump 使用“-a -d”选项,然后对输出使用“排序”,但数据中的换行符会使排序后的输出不可用。但是基本比较,不管有什么变化,就足够了。

【讨论】:

【参考方案4】:

如果您只是对架构感兴趣:

您可以通过使用这些选项的组合来一次仅转储一个表的架构来创建您的差异表。然后,您可以单独比较它们或将它们全部按已知顺序归类到一个文件中。

-s, --schema-only           dump only the schema, no data
-t, --table=TABLE           dump the named table(s) only

要生成表的列表以提供给上述内容,请查询information_schema.tables

【讨论】:

【参考方案5】:

截至 2010 年 5 月,patch to pg_dump 的存在可能对所有对此感兴趣的人有所帮助 - 它为该实用程序添加了“--ordered”选项:

使用 --ordered 将对数据进行排序 主键或唯一索引,如果有的话 存在,并使用“最小” 订购(即最少数量的 唯一订单所需的列)。

请注意, --ordered 可能会破坏您的 如果您尝试订购数据库服务器 非常大的表,因此请谨慎使用。

我没有测试,但我想值得一试。

【讨论】:

你好 Zifot,链接坏了,还有 2 年过去了,想试一试,但找不到其他参考。你能提供工作链接吗?谢谢。 一个非常有趣的补丁/添加,很遗憾没有发布。【参考方案6】:

PostgreSQL 的行为具有不确定性并不罕见 - 可能是计时器触发的重组过程或类似的事情发生在后台。此外,我不知道有一种方法可以强制 pg_dump 在连续运行时重现位相同的输出。

我建议更改您的比较逻辑,因为您的比较行为不端 - 它报告差异,而两个转储代表相同的数据库状态。这当然意味着一些额外的工作,但在我看来是解决问题的正确方法。

【讨论】:

【参考方案7】:

如果性能不如您可以使用的顺序重要:

COPY (select * from your_table order by some_col) to stdout
      with csv header delimiter ',';

见COPY (9.5)

【讨论】:

以上是关于Postgres pg_dump 每次都以不同的顺序转储数据库的主要内容,如果未能解决你的问题,请参考以下文章

postgres 文件系统级别的备份 pg_dump

postgres 文件系统级别的备份 pg_dump

使用pg_dump导出postgres db不起作用,数据库“db_name”不存在

使用 pg_dump 将 Postgres 从 Windows 迁移到 Linux 时如何选择正确的排序规则来创建数据库?

当端口 5432 被阻塞时,来自远程服务器的 pg_dump postgres 数据库

postgres 数据库备份(保证pg_dump的命令是全局的)