PostgresSql VACUUM 剖析
為什么需要 Vacuum
MVCC
MVCC:Multi-Version Concurrency Control,即多版本并發(fā)控制。
PostgreSQL 使用多版本并發(fā)控制(MVCC)來支持高并發(fā)的事務處理,同時保持數據的一致性和隔離性。MVCC 是一種用于管理數據庫并發(fā)操作的技術,它允許多個事務同時訪問同一數據,而不會產生沖突或阻塞。
MVCC 的工作原理
-
版本化:
PostgreSQL 為表中的每行數據存儲多個版本。當一個事務更新一行數據時,它不會立即覆蓋原始數據,而是創(chuàng)建該數據的新版本。
-
事務ID:
每個事務被分配一個唯一的事務ID(XID),該ID 用于跟蹤數據的變更。 -
快照:
當一個事務開始時,它會創(chuàng)建一個快照,該快照是數據庫在某一時刻的狀態(tài)。即使其他事務在該事務進行時對數據進行了更改,該事務仍然可以看到它開始時的數據庫狀態(tài)。 -
可見性規(guī)則:
MVCC 通過一組可見性規(guī)則來確定事務可以看到哪些數據版本。通常,一個事務只能看到在它開始之前已經提交的其他事務所做的更改。 -
垃圾回收:
PostgreSQL 使用VACUUM? 命令來清理不再需要的數據版本,釋放空間。VACUUM? 操作由系統(tǒng)自動調度,也可以手動執(zhí)行。
MVCC 的關鍵特點:
- 無鎖讀取:
MVCC 允許其他事務在讀取數據時不被鎖定,因為它們可以訪問數據的舊版本。 - 寫入時復制:
當數據被更新時,PostgreSQL 會復制舊版本的數據并創(chuàng)建新版本,而不是直接在原地修改。 - 隔離級別:
PostgreSQL 支持不同的事務隔離級別,如讀未提交(Read Uncommitted)、讀已提交(Read Committed)、可重復讀(Repeatable Read)和串行化(Serializable)。隔離級別決定了事務可以看到其他事務更改的時間點。 - 性能:
MVCC 可以提高數據庫的性能,因為它減少了鎖的爭用和事務間的阻塞。 - 一致性:
通過使用快照,MVCC 確保了事務在整個過程中看到的是一致性的數據視圖。
MVCC 的挑戰(zhàn):
- 表膨脹:
由于多版本的存在,表可能會膨脹,需要定期維護。 - 長事務:
長事務可能導致較舊的數據版本長時間不被回收,從而影響性能和空間。 - 系統(tǒng)資源:
MVCC 需要額外的系統(tǒng)資源來管理多個數據版本。
MVCC 是 PostgreSQL 強大并發(fā)控制機制的核心,它使得數據庫能夠高效地處理大量的并發(fā)事務,同時保持數據的一致性和隔離性。
表膨脹
多版本并發(fā)控制機制(MVCC)的原理在于,當它需要更改某塊數據的時候,它不會直接去更改,而是會創(chuàng)建這份數據的新版本,在新版本進行更改,所以會存儲多份版本,每個事務能看見哪一份版本的數據,由事務隔離級別控制。
MVCC引入了一個問題,如何消除老舊的、沒有使用的無用數據(版本),目前主流上有3種處理實現方式:
來看看各種數據庫的解決方式:
-
以Oracle為代表的,把舊版本數據放入UNDO,新數據放入REDO,然后更改數據。這種方式,舊版本的數據放入了UNDO,所以可以有效避免膨脹。
-
以SQL Server為代表的,把舊版本的數據寫入專門的臨時表空間,新數據寫入日志,然后去更改數據。這種方式,舊版本的數據放入了專門的臨時表空間,所以也可以有效地避免膨脹。
-
以PostgreSQL為代表的,把舊版本標示為無效,新數據寫入日志,成功后把新版本的數據寫入新的位置。這種實現機制是導致數據膨脹嚴重的一個重要原因,因為舊版本的數據雖然表示為無效狀態(tài),但是沒被回收前還是占據存儲空間。
Vacuum 工作原理
PostgreSQL的表膨脹清理就需要依賴vacuum,vacuum的主要任務就是清理表和索引中不需要的數據(dead tuples),為新加入的數據清理出來空間。
Vacuum
PostgreSQL中的VACUUM?命令是一種數據庫維護任務,用于清理數據庫中的無用空間(也稱為“dead tuples”或“ghost tuples”),并防止表膨脹。VACUUM?還更新數據庫的統(tǒng)計信息,這些信息由查詢優(yōu)化器用來選擇最有效的查詢計劃。以下是VACUUM?如何工作的詳細步驟:
- 標記刪除:
PostgreSQL使用一種稱為標記-清除(mark-sweep)的垃圾收集機制。當DELETE或UPDATE命令刪除或修改表中的數據行時,原始數據行不會被立即從存儲中移除,而是被標記為“已刪除”。這意味著這些行仍然占用空間,但對查詢來說是不可見的。 - 移除元組:
這里的移除dead tuples只是標記為可重用該空間,并沒有真正物理刪除。所以vacuum清理表后,表的實際空間并沒有減小。dead tuples在做移除標記后,vacuum會重新排列剩余的元組以進行碎片化整理。然后,需要更新目標表的VM(可見性映射文件)和FSM(空閑空間映射文件)。 - 更新統(tǒng)計信息:
?VACUUM?收集有關表和索引中數據分布的統(tǒng)計信息,并將這些信息存儲在系統(tǒng)目錄中。這些統(tǒng)計信息對于查詢優(yōu)化器來說是至關重要的,因為它們幫助優(yōu)化器決定如何執(zhí)行查詢。
?
VACUUM?在這段時間刪除的數據,并不會從此磁盤上刪除,只是將數據標為可刪除,這部分可刪除的空間會出現以下兩種情況:
- 當有新的數據進行,新數據會寫入至這部分可刪除的空間中,即老數據從磁盤上移除了
- 系統(tǒng)執(zhí)行
vacuum full? ,PgSql 會重新整理所有的元組(Tuples),最終將數據從磁盤上移除,這一步比較耗費資源和時間,有可能鎖表,生產環(huán)境慎用!
Vacuum Full
Vacuum Full和Vacuum最大的不同就是,Vacuum Full是物理刪除dead tuples,并把釋放的空間重新交給操作系統(tǒng),所以在vacuum full后,表的大小會減小為實際的空間大小。其處理過程和 vacuum 大不相同,處理步驟如下:
-
創(chuàng)建排它鎖
vacuum full 開始執(zhí)行時,系統(tǒng)會先對目標創(chuàng)建一個AccessExclusiveLock ,不允許外界再進行訪問(為后面拷貝做準備)。
-
創(chuàng)建新表
系統(tǒng)會創(chuàng)建一張表結構和源表一模一樣的新表,方便后續(xù)做數據操作。
-
復制數據
掃描目標表,把表中的live tuples 拷貝到新表中。
-
替換數據表
刪除目標表,在新表上,重新創(chuàng)建索引,更新VM, FSM以及統(tǒng)計信息,相關系統(tǒng)表等。
綜上所述,vacuum full的本質是生成一個新的數據文件,然后把原有表的live tuples存放到該數據文件中。對比vacuum, vacuum full缺點就是在執(zhí)行期間不能對表進行訪問,由于需要往新表中導入live tuples數據,其執(zhí)行效率也會很慢。優(yōu)點是執(zhí)行后,表空間只存放live tuples,沒有冗余的dead tuples,在執(zhí)行查詢效率上會有所提高。
但是,vacuum full 也有存在的問題,在執(zhí)行過程中,它會block所有對表的訪問,不只是寫操作,讀操作也會全部block。很多情況下這是不可接受的,尤其是生產環(huán)境。
Vacuum 的好處
PostgreSQL中的VACUUM?命令具有多個好處,主要包括:
- 回收空間:
VACUUM?可以清理數據庫中的無用空間,即那些被標記為“已刪除”的行占用的空間,從而釋放這些空間供其他數據使用。 - 更新統(tǒng)計信息:
VACUUM?會更新數據庫的統(tǒng)計信息,這些信息對于查詢優(yōu)化器選擇最有效的查詢計劃至關重要。 - 維護索引:
VACUUM?還會維護索引,刪除索引中指向已刪除數據行的條目,并可能重建索引以優(yōu)化性能。 - 防止表膨脹:隨著時間推移,表中的死元組會越來越多,這會導致存儲空間利用率下降,
VACUUM?可以防止這種情況。 - 提高查詢性能:通過清理無用的元組,
VACUUM?可以減少查詢需要遍歷的數據量,從而提高查詢性能。 - 自動回收空間:
VACUUM?可以自動回收已經釋放的空閑空間,減少了數據庫管理員的手動干預。
?VACUUM?是PostgreSQL數據庫維護和性能優(yōu)化的重要組成部分,正確理解和運用VACUUM?命令及其變種,對于保持數據庫的良好運行狀態(tài)具有重要意義。
Vacuum 的最佳實踐
PostgreSQL中的VACUUM?操作是數據庫維護的重要組成部分,以下是一些最佳實踐:
- 定期執(zhí)行VACUUM:根據業(yè)務負載和表的更新頻率,制定合理的VACUUM策略,特別是對于頻繁更新的大表。
- 啟用并調優(yōu)Autovacuum:依賴Autovacuum來自動維護數據庫健康。通過調整
autovacuum_vacuum_threshold?和autovacuum_vacuum_scale_factor?等參數,可以更精確地控制自動VACUUM的觸發(fā)時機。 - 考慮使用VACUUM FULL:雖然
VACUUM FULL?可以最大程度地釋放磁盤空間,但由于它可能會鎖定表并需要較長時間執(zhí)行,建議在業(yè)務低峰期使用,并確保有足夠的磁盤空間來創(chuàng)建表的新副本。 - 監(jiān)控Vacuum活動:利用
pg_stat_user_tables?視圖或其他監(jiān)控工具,了解Vacuum操作的狀態(tài)和效果,以便及時調整相關參數。 - 不要無故運行手動VACUUM或ANALYZE:Autovacuum通常可以很好地管理數據庫,除非有特殊情況,否則不必頻繁手動執(zhí)行這些操作。
- 在數據批量加載后運行ANALYZE:在大量新數據被插入數據庫后,運行ANALYZE以確保統(tǒng)計信息的準確性,從而幫助查詢優(yōu)化器制定更有效的查詢計劃。
- 收集數據庫信息:在調整參數或實施手動VACUUM/ANALYZE之前,收集有關數據庫的足夠信息,如表的行數、死元組數、最后一次VACUUM/ANALYZE的時間等,以便做出更明智的決策。
通過遵循這些最佳實踐,可以確保數據庫的性能和健康狀況得到良好的維護。
?
參考文檔:
PostgreSQL的表膨脹與Vacuum和Vacuum Full - 明礬 - 博客園
深入淺出 PostgreSQL VACUUM 流程,全面掌控數據健康與性能! - ByteZoneX社區(qū)
blog/202405/20240530_01.md at master · digoal/blog · GitHub
?

浙公網安備 33010602011771號