簡體   English   中英

Postgres pg_dump每次都以不同的順序轉儲數據庫

[英]Postgres pg_dump dumps database in a different order every time

我正在編寫一個PHP腳本(也使用linux bash命令),它將通過執行以下操作來運行測試用例:

我正在使用PostgreSQL數據庫(8.4.2)...

1.)創建DB 2.)修改DB 3.)存儲DB的數據庫轉儲(pg_dump)

4.)通過執行步驟1.)和2.)進行回歸測試,然后進行另一個數據庫轉儲並將其(差異)與步驟3中的原始數據庫轉儲進行比較。)

但是,我發現pg_dump不會總是以相同的方式轉儲數據庫。 它每次都會以不同的順序轉儲。 因此,當我對兩個數據庫轉儲執行diff時,比較將導致兩個文件不同,當它們實際上是相同的時,只是以不同的順序。

我可以采用不同的方式來做pg_dump嗎?

謝謝!

這是一個方便的腳本,用於預處理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以在diffs中使用顏色:

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

注意:如果已創建/刪除/重命名表,請記住在對新轉儲進行后處理之前刪除所有.sql文件。

這里值得區分模式和數據。 模式以相當確定的順序轉儲,大多數對象按字母順序排列,受到對象間依賴性的約束。 在一些有限的情況下,訂單沒有完全約束,並且可能對外部觀察者來說是隨機的,但可能會在下一個版本中得到修復。

另一方面,數據以磁盤順序轉儲。 這通常是您想要的,因為您希望轉儲速度快,而不是使用大量的資源來進行排序。 您可能正在觀察的是,當您“修改數據庫”時,您正在執行更新,這將實際刪除舊值並在最后附加新值。 這當然會擾亂你的差異化戰略。

pg_comparator可能更適合您的工具

不可能強制pg_dump以任何特定順序轉儲數據,因為它以磁盤順序轉儲數據 - 這種方式要快得多。

您可以為pg_dump使用“-a -d”選項然后“排序”輸出,但數據中的換行將使排序的輸出無法使用。 但是對於基本的比較,無論是否有任何改變,都足夠了。

截至2010年5月存在pg_dump補丁 ,可能對所有對此事感興趣的人都有幫助 - 它為此實用程序添加了“--ordered”選項:

使用--ordered將按主鍵或唯一索引(如果存在)對數據進行排序,並使用“最小”排序(即唯一順序所需的最少列數)。

請注意,如果您嘗試訂購非常大的表,則--ordered可能會破壞您的數據庫服務器,因此請謹慎使用。

我沒有測試它,但我想這值得一試。

如果您只對架構感興趣:

您可以通過逐個使用這些選項的組合來執行diff表,一次只轉儲一個表的模式。 然后,您可以單獨比較它們,或者以已知順序將它們全部記錄到一個文件中。

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

要生成要提供給上面的表的列表,請查詢information_schema.tables

PostgreSQL行為不確定性並不罕見 - 可能是定時器觸發的重組過程或類似的事情發生在后台。 此外,我不知道有一種方法可以強制pg_dump在連續運行時重現相同的輸出。

我建議更改您的比較邏輯,因為它是您的行為不端的比較 - 它報告差異,而兩個轉儲表示相同的數據庫狀態。 這當然意味着一些額外的工作,但在我看來是解決問題的正確方法。

如果性能不如訂單那么重要,您可以使用:

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

COPY(9.5)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM