表膨脹和索引膨脹是 PostgreSQL 一直以來要面對的問題,至今仍常見於 PostgreSQL 書籍、演講或技術部落格的討論中。如果仔細翻找 PostgreSQL 發展史,會發現幾乎每一個版本都在持續挑戰這個問題。

10 Things I Hate About PostgreSQL

這篇 2013 年簡報所提,VACUUM (目的之一為解決 Bloating) 是一個很複雜的課題,PostgreSQL 從過去的人工判斷,到現在的自動回收 (AUTOVACUUM)。

圖一

圖一是簡報第 9 頁,如果翻找目前 PostgreSQL 最新的原始碼,程式碼這段 full exclusive lock 說明仍然存在。(詳見 src/backend/commands/vacuumlazy.c)

有聽過我演講的人,應該還會記得 PostgreSQL 的哲學與 Oracle / SQL Server / MySQL 有很大的不同。PostgreSQL 習慣把「垃圾回收」延後處理,而其它資料庫習慣同時一併處理完。

所以「通常」PostgreSQL 寫入資料會較快,因為可以先不管「垃圾回收」,但其它資料庫習慣寫入時一併處理掉「垃圾」,所以當下感覺比較慢。可是,當 PostgreSQL 決定要處理「垃圾」時,因為需要撥力氣處理之前沒清的垃圾,所以寫入的效能勢必會受到影響,而且如果累積的垃圾量太大,影響寫入的效能的時間會更久,甚至積重難返造成 Bloating,事後還要花更多力氣恢復 (另外執行 pg_repack 等程序)。

因此,很多 PostgreSQL 專家建議 AUTOVACUUM 要 aggressively tuning,可是 aggressively tuning 要依據不同場景的不同個案有著不同的設定,這一直是個難題。簡單來說,不同的需求會有不同的設定,可是資料庫通常是一體性,會給許多不同場景及需求使用 (例如電商 / CRM / ERP / 報表系統所用,而每個場景的 aggressively tuning 可能有所不同),此時的 aggressively tuning 無法做到全局最佳化,而且設定的複雜性很高,因為要找到各場景的平衡點。

圖二

再根據簡報第 10 頁所言 (圖二),最好的避免方法是什麼?其一就是少用 long-running transactions。先前有很多 PostgreSQL 專家批評 MySQL 的重點之一,就是 MySQL 對 long-running transactions 的處理能力較弱 (其實只是某些少數場景小較弱),但 PostgreSQL 自己本身也是無法避免 long-running transactions 帶來的傷害。

最後,好消息是下一版本 PostgreSQL 9.7 會將 VACUUM 優化視為重點之一,同時也可能引入 Parallel Vacuum,繼續挑戰 Bloating 的問題。讓我們拭目以待。