解決PostgreSQL表膨脹

轉載地址:https://www.timbotetsu.com/blog/postgresql-bloatbusters/

PostgreSQL表膨脹終結者

無論是DBA還是開發者,只要工作中使用PostgreSQL,多多少少都會遇到vacuum:DBA需要配置vacuum,開發者遇到因vacuum導致的數據庫性能下降、慢查詢問題。

背景

vacuum對開發者來說是個黑盒,DBA知道vacuum很重要,vacuum的配置也很重要。不怎麼熟悉vacuum的人只知道vacuum是清理數據庫的垃圾收集器。有人會問,vacuum是怎麼清理數據庫的。可在官方文檔中找到十分詳細的答案,在這裏只做個簡短的概要。

處理數據時,PostgreSQL會爲每一個客戶端提供單獨的快照。客戶端對快照中的數據進行更新和刪除,一些數據最終變成過期數據,但它們仍存在於數據庫中,還佔用表數據文件和索引數據文件的空間。因此數據文件中會存在碎片,引起整體數據庫性能下降。這時候vacuum出來幹活了,vacuum的主要任務就是清理表和索引中不需要的數據(死數據),爲新加入的數據清理出來空間。

世界並不完美,vacuum也有存在的問題。比如,vacuum完成清理工作後,那些空間並沒有真正被釋放掉,只能被vacuum清理過的表和索引所利用。雖然看上去表和索引大小都已經減少了,但是實際上和vacuum清理前的大小是一樣。這讓很多剛開始使用Postgres的用戶感到困惑。

還有,某些場景下vacuum比較無能爲力,無法有效完成工作。比如執行空事務,vacuum會推遲清理死數據導致表和索引膨脹。空事務,甚至經常執行長事務都會對數據庫有影響,應避免這些操作。

還有個有趣的地方,假設有一張表上有大量索引,表上還有密集的更新操作。遇到這樣的情況,大量更新會觸發一次新的vacuum,有可能會發現這張表上有無窮無盡的vacuum在執行。無論怎麼修改vacuum的配置都沒有用,結果導致——表膨脹了。

好像沒有什麼vacuum配置有用,也無法拿回佔用的空間。當然,Postgres還有個vacuum full操作可以實現,但它會block所有對錶的訪問,不只是寫操作,讀操作也會全部block。很多情況下這是不可接受的,尤其是生產環境。

還是有門路的,PostgresSQL是開源的,還有個很棒的社區。社區爲PostgreSQL提供了很多工具,並且有些工具能夠突破vacuum full的限制,在不阻止表的訪問的情況下完成vacuum full的功能。

pg_repack

第一個工具是:pg_repack。它有點像吃了藥的vacuum full,創建一個新表,將數據從舊錶移動到新表。爲了避免表被獨佔鎖定,創建了一個額外的日誌表來記錄原始表的改動,還添加了一個把INSERT / UPDATE / DELETE操作記錄到日誌表的觸發器。當原始表中的數據全部導入到新表中,索引重建完畢,日誌表的改動全部完成,pg_repack會連同新索引,用新表替換舊錶,並將原舊錶Drop掉。整個過程非常簡單,非常可靠,但是需要注意的是——需要額外剩餘足夠的磁盤空間(原表大小 + 索引 + 額外的日誌表空間)。

以上是pg_repack的主要功能,但pg_repack還有一些有意思的功能,可以讓你:

  • 僅處理沒有父表的索引
  • 在不同的表空間中移動表和索引,比如在快速的SSD和慢速的HDD存儲分區之間進行移動歸檔操作,這樣有助於平衡client的IO
  • 執行根據指定columns進行CLUSTER(聚簇)重排序
  • 通過並行工作的workers加速索引建立
  • 取消阻礙pg_repack的查詢

pg_repack看起來很不錯,重視速度,所以應該要記住,不正確的使用會導致大量磁盤IO,降低client的查詢性能。

pgcompacttable

另一個工具是:pgcompacttable(也被稱爲compactor),是另一種用於壓縮表和索引,達到理想大小的工具。

pgcompacttable的工作方式和pg_repack不一樣。它使用PostgreSQL的一個有趣特性,在執行INSERT和UPDATE操作時,會將所有新版本的行移到表最開始的可用空間。這個特性十分重要,因爲如果從末端反向開始更新所有行,最終所有可用空間被這些行填充,並將表尾部的空間全部釋放以便讓定期vacuum進行truncate。它使用特殊的系統column——ctid,纔有可能更新行,並將行從表末端移到表開頭。這樣一來,pgcompacttable通過批量更新和vacuum強制PostgreSQL將行數據在表中移動,最終整個表被整理壓縮得很好。

pgcompacttable還有一些額外的特性和pg_repack相似,可以說一嘴:

  • 只處理沒有父表索引
  • 能夠調整pgcompacttable的影響

總之,pg_repack可能會導致數據庫性能暫時下降,pgcompacttable則是一個更安全的選項。後者不需要爲表維護預留空間(但仍需要爲索引重建保留空間),並且能夠在壓縮表的同時保證client的查詢性能。

結論

選誰?以下是個簡短問卷能幫你方便做選擇:

  1. 數據庫是否需要保證性能?是否需要保證client查詢性能?

    是 - pgcompacttable,否 - pg_repack

  2. 是否需要在表空間之間移動表或索引?

    是 - pg_repack,否 - pgcompacttable

  3. 是否有預留的空間進行維護?

    是 - pg_repack,否 - pgcompacttable

不管怎樣,將兩個工具都放在服務器上總不會錯的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章