PostgreSQL的表膨脹與Vacuum和Vacuum Full


為什么會有表膨脹--多版本並發控制機制

多版本並發控制機制(MVCC)的原理在於,當它需要更改某塊數據的時候,它不會直接去更改,而是會創建這份數據的新版本,在新版本進行更改,所以會存儲多份版本,每個事務能看見哪一份版本的數據,由事務隔離級別控制。

MVCC引入了一個問題,如何消除老舊的、沒有使用的無用數據(版本),目前主流上有3種處理實現方式:

來看看各種數據庫的解決方式:

第一種:以Oracle為代表的,把舊版本數據放入UNDO,新數據放入REDO,然后更改數據。這種方式,舊版本的數據放入了UNDO,所以可以有效避免膨脹。

第二種,以SQL Server為代表的,把舊版本的數據寫入專門的臨時表空間,新數據寫入日志,然后去更改數據。這種方式,舊版本的數據放入了專門的臨時表空間,所以也可以有效地避免膨脹。

第三種,以PostgreSQL為代表的,把舊版本標示為無效,新數據寫入日志,成功后把新版本的數據寫入新的位置。這種實現機制是導致數據膨脹嚴重的一個重要原因,因為舊版本的數據雖然表示為無效狀態,但是沒被回收前還是占據存儲空間。

PostgreSQL清理表膨脹之vacuum

PostgreSQL的表膨脹清理就需要依賴vacuum,vacuum的主要任務就是清理表和索引中不需要的數據(dead tuples),為新加入的數據清理出來空間。

vacuum的執行過程主要分為以下三步:

    1. 清除dead tuples指向的index tuples

        該過程中,vacuum會順序掃描目標表,並構建一個dead tuples組成的list鏈表,該list鏈表會存儲在maintenance_work_mem緩存中。然后vacuum根據dead  tuples list移除dead tuples指向的index。

    2. 移除dead tuples,更新VM和FSM

        這里的移除dead tuples只是標記為可重用該空間,並沒有真正物理刪除。所以vacuum清理表后,表的實際空間並沒有減小。dead tuples在做移除標記后,vacuum會重新排列剩余的元組以進行碎片化整理。然后,需要更新目標表的VM(可見性映射文件)和FSM(空閑空間映射文件)。

    3. 更新統計信息和相關系統表

       需要更新vacuum目標表的統計信息(以適應最新的查詢優化)和相關系統表。

但是vacuum也有存在的問題。比如,vacuum完成清理工作后,那些空間並沒有真正被釋放給操作系統,只能被vacuum清理過的表和索引所利用。

PostgreSQL清理表膨脹之vacuum full

Vacuum Full和Vacuum最大的不同就是,Vacuum Full是物理刪除dead tuples,並把釋放的空間重新交給操作系統,所以在vacuum full后,表的大小會減小為實際的空間大小。其處理過程和vacuum大不相同,處理步驟如下:

    1.  vacuum full開始執行時,系統會先對目標創建一個AccessExclusiveLock ,不允許外界再進行訪問(為后面拷貝做准備),然后創建一個表結構和目標表相同的新表。

    2. 掃描目標表,把表中的live tuples 拷貝到新表中。

    3. 刪除目標表,在新表上,重新創建索引,更新VM, FSM以及統計信息,相關系統表等。

    所以,vacuum full的本質是生成一個新的數據文件,然后把原有表的live tuples存放到該數據文件中。對比vacuum, vacuum full缺點就是在執行期間不能對表進行訪問,由於需要往新表中導入live tuples數據,其執行效率也會很慢。優點是執行后,表空間只存放live tuples,沒有冗余的dead tuples,在執行查詢效率上會有所提高。

當然,vacuum full 也有存在的問題,在執行過程中,它會block所有對表的訪問,不只是寫操作,讀操作也會全部block。很多情況下這是不可接受的,尤其是生產環境。

 

如何解決vacuum或vacuum full 帶來的問題,社區也提供了pg_squeeze,pg_repack等工具,下回分解。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM