21

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

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

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

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

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

有没有不同的方法可以做 pg_dump?

谢谢!

4

7 回答 7

15

这是一个方便的脚本,用于预处理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 以在差异中使用颜色:

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

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

于 2010-04-22T07:00:22.230 回答
14

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

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

可能更适合您的目的的工具是pg_comparator

于 2010-02-01T19:16:39.220 回答
10

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

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

于 2010-02-01T19:02:55.027 回答
3

如果您只对架构感兴趣:

您可以通过使用这些选项的组合来一次只为一个表转储模式来制作您的差异表。然后,您可以单独比较它们或以已知顺序将它们全部归类到一个文件中。

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

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

于 2010-02-01T19:54:25.197 回答
3

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

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

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

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

于 2010-08-10T11:55:39.593 回答
1

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

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

于 2010-02-01T18:16:06.767 回答
1

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

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

参见副本 (9.5)

于 2017-07-19T14:25:48.517 回答