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

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

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

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

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

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

有没有不同的方式可以去做pg_dump?

谢谢!

Solutions Collecting From Web of "Postgres pg_dump每次都以不同的顺序转储数据库"

强制pg_dump以任意顺序转储数据是不可能的,因为它按照磁盘顺序转储数据 – 这样做速度要快得多。

您可以对pg_dump使用“-a -d”选项,然后使用“sort”输出,但是数据中的换行符会使得排序的输出不可导入。 但是对于基本的比较,是否有任何改变就足够了。

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

https://github.com/akaihola/pgtricks

pg_dump_splitsort.py将转储分割成以下文件:

  • 0000_prologue.sql :一切到第一个COPY
  • 0001_<schema>.<table>.sql


    NNNN_<schema>.<table>.sql按第一个字段排序的每个表的数据
  • 9999_epilogue.sql :上次COPY后的所有内容

表数据文件被编号,所以可以使用所有文件的简单排序连接重新创建数据库:

 $ cat *.sql | psql <database> 

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

 $ meld old-dump/ new-dump/ 

在版本控制中存储转储也给出了一个体面的观点。 以下是如何配置git在diff中使用颜色:

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

注意:如果您创建/删除/重命名表,请记住删除所有.sql文件,然后再处理新的转储。

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

另一方面,数据按照磁盘顺序转储。 这通常是你想要的,因为你想要转储是快速的,而不是使用疯狂的资源量进行排序。 你可能会观察到的是,当你“修改数据库”时,你正在做一个UPDATE,它实际上会删除旧值并在最后附加新值。 这当然会打乱你的差异战略。

一个可能更适合你的目的的工具是pg_comparator 。

截至2010年5月,存在对pg_dump的修补程序,对所有对这个问题感兴趣的人可能都会有所帮助 – 它为此实用程序添加了“-ordered”选项:

使用–ordered将按主键或唯一索引(如果存在)对数据进行排序,并使用“最小”排序(即唯一顺序所需的最少列数)。

请注意,如果您尝试订购非常大的表格,订购可能会粉碎您的数据库服务器,请谨慎使用。

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

PostgreSQL的行为不确定 – 也许是定时器触发的重组过程或类似于后台发生的事情。 此外,我不知道有办法强制pg_dump在连续运行中重现一个位相同的输出。

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

如果您只是对模式感兴趣:

您可以通过使用这些选项的组合来一次只转储一个表的模式来执行差异表。 然后,您可以单独比较它们,也可以按已知顺序将它们全部加载到一个文件中。

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

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

如果性能不如订单重要,您可以使用:

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

见COPY(9.5)