PostgreSQL 資料庫需要定期維護,稱為清理。對於許多安裝,讓自動清理常駐程式執行清理就足夠了,這在第 24.1.6 節中描述。您可能需要調整其中描述的自動清理參數,以針對您的情況獲得最佳結果。某些資料庫管理員會希望用手動管理的 VACUUM
命令來補充或替換常駐程式的活動,這些命令通常由 cron 或 Task Scheduler 腳本按照排程執行。若要正確設定手動管理的清理,必須了解接下來幾個小節中討論的問題。依賴自動清理的管理員可能仍然希望略讀這些材料,以幫助他們了解和調整自動清理。
PostgreSQL 的 VACUUM
命令必須定期處理每個資料表,原因如下:
正如以下小節所解釋的,每個原因都要求執行不同頻率和範圍的 VACUUM
操作。
VACUUM
有兩種變體:標準 VACUUM
和 VACUUM FULL
。VACUUM FULL
可以回收更多磁碟空間,但執行速度要慢得多。此外,標準形式的 VACUUM
可以與生產資料庫操作平行執行。(諸如 SELECT
、INSERT
、UPDATE
和 DELETE
等命令將繼續正常運作,但您無法使用諸如 ALTER TABLE
等命令修改資料表的定義,因為它正在清理。)VACUUM FULL
需要對其正在處理的資料表進行 ACCESS EXCLUSIVE
鎖定,因此無法與資料表的其他使用平行完成。因此,通常管理員應盡力使用標準 VACUUM
並避免 VACUUM FULL
。
VACUUM
會產生大量的 I/O 流量,這可能會導致其他作用中工作階段的效能不佳。可以調整組態參數以減少背景清理對效能的影響 — 請參閱第 19.4.4 節。
在 PostgreSQL 中,列的 UPDATE
或 DELETE
不會立即移除該列的舊版本。這種方法對於獲得多版本並行控制的好處是必要的 (MVCC,請參閱第 13 章):在其他交易可能仍可看到該列版本時,不得刪除該版本。但最終,過時或已刪除的列版本不再對任何交易感興趣。它佔用的空間必須回收,以便新列重複使用,以避免磁碟空間需求無限增長。這是透過執行 VACUUM
來完成的。
標準形式的 VACUUM
會移除資料表和索引中的已失效列版本,並將空間標記為可供未來重複使用。但是,除非資料表結尾的一個或多個頁面完全空閒,並且可以輕鬆獲得獨佔資料表鎖定,否則它不會將空間返回給作業系統。相反,VACUUM FULL
會透過寫入沒有已失效空間的資料表檔案的完整新版本來主動壓縮資料表。這可以最大限度地減少資料表的大小,但可能需要很長時間。它還需要額外的磁碟空間來儲存資料表的新副本,直到操作完成。
例行清理的通常目標是經常執行標準 VACUUM
,以避免需要 VACUUM FULL
。自動清理常駐程式嘗試以這種方式運作,事實上永遠不會發出 VACUUM FULL
。在這種方法中,其想法不是保持資料表在其最小大小,而是維持磁碟空間的穩定狀態使用量:每個資料表佔用的空間相當於其最小大小,加上清理執行之間使用的空間量。儘管 VACUUM FULL
可用於將資料表縮小回其最小大小並將磁碟空間返回給作業系統,但如果資料表在未來會再次增長,則這樣做沒有太大意義。因此,對於維護大量更新的資料表而言,適度頻繁的標準 VACUUM
執行優於不頻繁的 VACUUM FULL
執行。
有些管理者偏好自行排程清理,例如在負載量低的時候,於夜間執行所有工作。按照固定排程執行清理的困難點在於,如果某個表格的更新活動意外激增,可能會膨脹到需要 VACUUM FULL
才能真正回收空間的地步。使用自動清理常駐程式可以減輕這個問題,因為該常駐程式會根據更新活動動態排程清理。除非您的工作負載極具可預測性,否則完全停用此常駐程式是不明智的。一種可能的折衷方案是設定該常駐程式的參數,使其僅對異常繁重的更新活動做出反應,從而防止事情失控,同時預期的排程 VACUUM
在負載正常時完成大部分工作。
對於未使用自動清理的人來說,一種典型的方法是在低使用率時段,每天排程一次全資料庫的 VACUUM
,並根據需要更頻繁地清理經常更新的表格。(有些更新頻率極高的安裝會每隔幾分鐘清理一次最繁忙的表格。) 如果叢集中有多個資料庫,請不要忘記對每個資料庫執行 VACUUM
;程式 vacuumdb 可能會有幫助。
當表格包含大量因大規模更新或刪除活動而產生的無效列版本時,單純的 VACUUM
可能無法令人滿意。如果您有這樣的表格,並且需要回收其佔用的過多磁碟空間,則需要使用 VACUUM FULL
,或者選擇 CLUSTER
或 ALTER TABLE
的表格重寫變體之一。這些指令會重寫整個表格的新副本,並為其建立新的索引。所有這些選項都需要 ACCESS EXCLUSIVE
鎖定。請注意,它們也會暫時使用額外的磁碟空間,約等於表格的大小,因為在新的表格和索引完成之前,無法釋放舊副本。
如果您有一個表格的全部內容會定期刪除,請考慮使用 TRUNCATE
進行刪除,而不是使用 DELETE
,然後執行 VACUUM
。TRUNCATE
會立即移除表格的全部內容,而無需後續的 VACUUM
或 VACUUM FULL
來回收現在未使用的磁碟空間。缺點是嚴格的 MVCC 語意會被違反。
PostgreSQL 查詢規劃器依賴於有關表格內容的統計資訊,以便產生良好的查詢計畫。這些統計資訊由 ANALYZE
指令收集,可以單獨呼叫,也可以作為 VACUUM
中的可選步驟。擁有合理準確的統計資訊非常重要,否則不良的計畫選擇可能會降低資料庫效能。
如果啟用了自動清理常駐程式,則每當表格的內容發生足夠大的變化時,它會自動發出 ANALYZE
指令。但是,管理者可能更喜歡依賴手動排程的 ANALYZE
操作,特別是如果知道表格上的更新活動不會影響 「有趣的」欄的統計資訊。該常駐程式嚴格地根據插入或更新的列數來排程 ANALYZE
;它不知道這是否會導致有意義的統計變化。
分割區和繼承子資料表的元組變更不會觸發父資料表的分析。如果父資料表為空或很少變更,則可能永遠不會由自動清理處理,並且不會收集整個繼承樹的統計資訊。為了使統計資訊保持最新,有必要手動在父資料表上執行 ANALYZE
。
與為了空間回收而進行清理一樣,頻繁更新統計資訊對於經常更新的表格比對於很少更新的表格更有用。但即使是經常更新的表格,如果資料的統計分佈沒有太大變化,也可能不需要更新統計資訊。一個簡單的經驗法則是考慮表格中欄位的最小值和最大值變化多少。例如,包含列更新時間的 timestamp
欄位,隨著列的加入和更新,其最大值將不斷增加;與包含網站上存取的頁面 URL 的欄位相比,此欄位可能需要更頻繁地更新統計資訊。URL 欄位可能同樣經常收到變更,但其值的統計分佈可能變化相對緩慢。
可以在特定表格,甚至只是表格的特定欄位上執行 ANALYZE
,因此如果您的應用程式需要,可以靈活地比其他統計資訊更頻繁地更新某些統計資訊。然而,在實務上,最好只是分析整個資料庫,因為這是一個快速的操作。ANALYZE
使用表格列的統計隨機抽樣,而不是讀取每一列。
雖然對 ANALYZE
頻率進行按欄位調整可能不會很有成效,但您可能會發現對 ANALYZE
收集的統計資訊的詳細程度進行按欄位調整是值得的。在 WHERE
子句中大量使用且具有高度不規則資料分佈的欄位,可能需要比其他欄位更精細的資料直方圖。請參閱 ALTER TABLE SET STATISTICS
,或使用 default_statistics_target 組態參數變更全資料庫的預設值。
此外,預設情況下,關於函數的選擇性資訊有限。但是,如果您建立使用函數呼叫的統計物件或運算式索引,則會收集關於該函數的有用統計資訊,這可以極大地改善使用該運算式索引的查詢計畫。
自動清理常駐程式不會為外部資料表發出 ANALYZE
指令,因為它無法確定多久執行一次會有用。如果您的查詢需要外部資料表上的統計資訊才能進行正確的規劃,最好在適當的排程上對這些表格執行手動管理的 ANALYZE
指令。
自動清理常駐程式不會為分割資料表發出 ANALYZE
指令。只有在父資料表本身發生變更時,才會分析繼承父資料表 - 對子資料表的變更不會觸發父資料表的自動分析。如果您的查詢需要父資料表上的統計資訊才能進行正確的規劃,則需要定期在這些表格上執行手動 ANALYZE
,以使統計資訊保持最新。
Vacuum 會維護每個資料表的可見性地圖,以追蹤哪些頁面僅包含已知對所有活動交易(以及所有未來交易,直到該頁面再次被修改)都可見的元組。這有兩個目的。首先,vacuum 本身可以在下次執行時跳過這些頁面,因為沒有任何需要清理的東西。
其次,它允許 PostgreSQL 僅使用索引來回答某些查詢,而無需參考底層資料表。由於 PostgreSQL 索引不包含元組可見性資訊,因此一般的索引掃描會提取每個匹配的索引條目的堆積元組,以檢查它是否應被目前的交易看到。另一方面,僅索引掃描會先檢查可見性地圖。如果已知頁面上的所有元組都可見,則可以跳過堆積提取。這在大型資料集上最有用,因為可見性地圖可以防止磁碟存取。可見性地圖遠小於堆積,因此即使堆積非常大,也很容易被快取。
PostgreSQL 的 MVCC 交易語意依賴於能夠比較交易 ID (XID) 號碼:插入 XID 大於目前交易 XID 的列版本是 “在未來”,並且不應對目前交易可見。但是由於交易 ID 的大小有限(32 位),因此運行時間較長的叢集(超過 40 億個交易)將遭受交易 ID 循環:XID 計數器循環到零,並且突然之間,過去的交易似乎在未來——這意味著它們的輸出變得不可見。簡而言之,災難性的資料遺失。(實際上,資料仍然存在,但是如果您無法存取它,這是一種冷酷的安慰。)為避免這種情況,至少每兩十億個交易就必須對每個資料庫中的每個資料表進行 vacuum。
定期 vacuum 解決問題的原因是 VACUUM
會將列標記為凍結,表示它們是由在過去充分提交的交易插入的,因此插入交易的影響肯定對所有目前和未來的交易都可見。正常的 XID 使用模數 232 算術進行比較。這意味著對於每個正常的 XID,有 20 億個 XID 是 “較舊的”,而 20 億個是 “較新的”;另一種說法是,正常的 XID 空間是循環的,沒有端點。因此,一旦使用特定的正常 XID 建立了列版本,無論我們談論哪個正常 XID,該列版本將在接下來的 20 億個交易中顯示為 “在過去”。如果列版本在超過 20 億個交易後仍然存在,它將突然顯示為在未來。為了防止這種情況,PostgreSQL 保留了一個特殊的 XID,FrozenTransactionId
,它不遵循正常的 XID 比較規則,並且始終被認為比每個正常的 XID 都要舊。凍結的列版本被視為插入 XID 為 FrozenTransactionId
,因此它們將對所有正常交易顯示為 “在過去”,而無論循環問題如何,因此此類列版本將有效直到被刪除,無論時間多長。
在 9.4 之前的 PostgreSQL 版本中,凍結是通過實際將列的插入 XID 替換為 FrozenTransactionId
來實現的,這在列的 xmin
系統欄位中可見。較新的版本僅設定一個標誌位,保留列的原始 xmin
以供可能的鑑識使用。但是,在從 9.4 之前的版本 pg_upgrade 的資料庫中,仍然可以找到 xmin
等於 FrozenTransactionId
(2) 的列。
另外,系統目錄可能包含 xmin
等於 BootstrapTransactionId
(1) 的列,表示它們是在 initdb 的第一階段插入的。與 FrozenTransactionId
類似,此特殊 XID 被視為比每個正常的 XID 都要舊。
vacuum_freeze_min_age 控制 XID 值必須有多舊,列上帶有該 XID 的列才會被凍結。如果將被凍結的列很快將再次被修改,則增加此設定可以避免不必要的工作,但是降低此設定會增加資料表必須再次 vacuum 的交易數量。
VACUUM
使用可見性地圖來確定必須掃描的資料表頁面。通常,即使這些頁面可能仍然具有具有舊 XID 值的列版本,它也會跳過沒有任何無效列版本的頁面。因此,普通的 VACUUM
並非總是會凍結資料表中每個舊的列版本。發生這種情況時,VACUUM
最終需要執行積極的 vacuum,這將凍結所有符合條件的未凍結 XID 和 MXID 值,包括來自所有可見但未全部凍結的頁面中的值。實際上,大多數資料表都需要定期進行積極的 vacuum。vacuum_freeze_table_age 控制 VACUUM
何時執行此操作:如果自上次此類掃描以來經過的交易數量大於 vacuum_freeze_table_age
減去 vacuum_freeze_min_age
,則掃描所有可見但未全部凍結的頁面。將 vacuum_freeze_table_age
設定為 0 會強制 VACUUM
始終使用其積極的策略。
資料表可以不進行 vacuum 的最長時間是 20 億個交易減去上次積極 vacuum 時的 vacuum_freeze_min_age
值。如果未對其進行 vacuum 的時間超過此時間,則可能導致資料遺失。為了確保不會發生這種情況,會對任何可能包含 XID 比配置參數 autovacuum_freeze_max_age 指定的年齡更大的未凍結列的資料表,調用自動 vacuum。(即使禁用自動 vacuum,也會發生這種情況。)
這意味著,如果資料表沒有以其他方式進行 vacuum,則大約每 autovacuum_freeze_max_age
減去 vacuum_freeze_min_age
個交易,將對其調用自動 vacuum。對於定期為回收空間目的而進行 vacuum 的資料表,這並不重要。但是,對於靜態資料表(包括接收插入,但不接收更新或刪除的資料表),沒有必要為回收空間而進行 vacuum,因此嘗試最大程度地延長在非常大的靜態資料表上強制執行自動 vacuum 的間隔可能很有用。顯然,您可以通過增加 autovacuum_freeze_max_age
或減少 vacuum_freeze_min_age
來做到這一點。
vacuum_freeze_table_age
的有效最大值為 0.95 * autovacuum_freeze_max_age
;高於此設定的值將被限制為最大值。高於 autovacuum_freeze_max_age
的值沒有意義,因為無論如何都會在該點觸發防止環繞 (anti-wraparound) 的自動清理 (autovacuum),而 0.95 的乘數留下了一些緩衝空間,以便在此之前執行手動的 VACUUM
。一般來說,vacuum_freeze_table_age
應設定為略低於 autovacuum_freeze_max_age
的值,留下足夠的空間,以便定期排程的 VACUUM
或由正常刪除和更新活動觸發的自動清理在該時間範圍內執行。設定得太接近可能會導致防止環繞的自動清理,即使表格最近已清理以回收空間,而較低的值會導致更頻繁的激進清理。
增加 autovacuum_freeze_max_age
(以及隨之而來的 vacuum_freeze_table_age
) 的唯一缺點是,資料庫叢集的 pg_xact
和 pg_commit_ts
子目錄會佔用更多空間,因為它必須儲存所有交易的回溯到 autovacuum_freeze_max_age
期限的回應狀態和 (如果啟用 track_commit_timestamp
) 時間戳記。回應狀態每個交易使用 2 位元,因此如果 autovacuum_freeze_max_age
設定為其允許的最大值 20 億,則預計 pg_xact
將增長到大約半個 GB,而 pg_commit_ts
將增長到大約 20GB。如果這相較於您的總資料庫大小而言微不足道,建議將 autovacuum_freeze_max_age
設定為其允許的最大值。否則,請根據您願意為 pg_xact
和 pg_commit_ts
儲存空間分配多少來設定。(預設值 2 億個交易轉換為大約 50MB 的 pg_xact
儲存空間和大约 2GB 的 pg_commit_ts
儲存空間。)
降低 vacuum_freeze_min_age
的一個缺點是,它可能會導致 VACUUM
執行無用的工作:如果該列版本很快被修改 (導致它取得一個新的 XID),則凍結列版本是浪費時間。因此,設定應足夠大,以便在列不太可能再更改之前不會凍結列。
為了追蹤資料庫中最舊的未凍結 XID 的時間,VACUUM
將 XID 統計資訊儲存在系統表格 pg_class
和 pg_database
中。特別是,表格的 pg_class
列的 relfrozenxid
欄包含在最近一次成功推進 relfrozenxid
的 VACUUM
結束時的最舊剩餘未凍結 XID (通常是最近一次激進的 VACUUM)。同樣地,資料庫的 pg_database
列的 datfrozenxid
欄是出現在該資料庫中的未凍結 XID 的下限 — 它只是資料庫內每個表格的 relfrozenxid
值的最小值。檢查此資訊的便捷方式是執行如下查詢
SELECT c.oid::regclass as table_name, greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as age FROM pg_class c LEFT JOIN pg_class t ON c.reltoastrelid = t.oid WHERE c.relkind IN ('r', 'm'); SELECT datname, age(datfrozenxid) FROM pg_database;
age
欄測量從截止 XID 到目前交易的 XID 的交易數量。
當指定 VACUUM
命令的 VERBOSE
參數時,VACUUM
會印出有關表格的各種統計資訊。這包括有關 relfrozenxid
和 relminmxid
如何推進以及新凍結的頁面數量的資訊。當自動清理記錄 (由 log_autovacuum_min_duration 控制) 報告由自動清理執行的 VACUUM
作業時,伺服器記錄中也會出現相同的詳細資訊。
VACUUM
通常只掃描自上次清理以來已修改的頁面,但只有在掃描了表格中可能包含未凍結 XID 的每個頁面時,才能推進 relfrozenxid
。當 relfrozenxid
比 vacuum_freeze_table_age
舊超過交易數時,當使用 VACUUM
的 FREEZE
選項時,或者當所有尚未完全凍結的頁面都恰好需要清理以移除已死亡的列版本時,會發生這種情況。當 VACUUM
掃描表格中尚未完全凍結的每個頁面時,它應將 age(relfrozenxid)
設定為略高於所使用的 vacuum_freeze_min_age
設定的值 (比自 VACUUM
開始以來開始的交易數量更多)。VACUUM
會將 relfrozenxid
設定為表格中剩餘的最舊 XID,因此最終值可能比嚴格要求的值更晚。如果在達到 autovacuum_freeze_max_age
之前,未在表格上發出 relfrozenxid
推進的 VACUUM
,則很快會強制對該表格進行自動清理。
如果由於某種原因自動清理無法從表格中清除舊的 XID,當資料庫中最舊的 XID 從環繞點達到四千萬個交易時,系統將開始發出類似這樣的警告訊息
WARNING: database "mydb" must be vacuumed within 39985967 transactions HINT: To avoid XID assignment failures, execute a database-wide VACUUM in that database.
(如提示中建議的那樣,手動 VACUUM
應修復此問題;但請注意,VACUUM
應由超級使用者執行,否則它將無法處理系統目錄,這會阻止它推進資料庫的 datfrozenxid
。) 如果忽略這些警告,系統將拒絕指派新的 XID,一旦剩餘的交易少於三百萬個直到環繞
ERROR: database is not accepting commands that assign new XIDs to avoid wraparound data loss in database "mydb" HINT: Execute a database-wide VACUUM in that database.
在這種情況下,任何已經進行中的交易都可以繼續,但只能啟動唯讀交易。修改資料庫記錄或截斷關係的操作將失敗。VACUUM
命令仍然可以正常執行。請注意,與早期版本中偶爾建議的不同,沒有必要或不希望停止 postmaster 或進入單一使用者模式以恢復正常操作。相反地,請按照以下步驟操作
age(transactionid)
很大的列來找到這些交易。應提交或回滾這些交易。age(backend_xid)
或 age(backend_xmin)
很大的列來找到這些交易。應提交或回滾這些交易,或者可以使用 pg_terminate_backend
終止會話。age(xmin)
或 age(catalog_xmin)
很大的槽。在許多情況下,這些槽是為複製到不再存在或已關閉很長時間的伺服器而建立的。如果您刪除仍然存在並且可能仍然嘗試連接到該槽的伺服器的槽,則可能需要重建該副本。VACUUM
。全資料庫的 VACUUM
最簡單;為了縮短所需時間,也可以在 relminxid
最舊的資料表上手動執行 VACUUM
命令。請勿在此情況下使用 VACUUM FULL
,因為它需要 XID,因此會失敗,除非在超級使用者模式下,它會消耗一個 XID,從而增加交易 ID 環繞的風險。也不要使用 VACUUM FREEZE
,因為它會執行超出恢復正常運作所需的最少工作量。在較早的版本中,有時需要停止 postmaster 並在單一使用者模式下 VACUUM
資料庫。在典型情況下,這已不再必要,應盡可能避免,因為這涉及系統停機。它也更具風險,因為它會停用旨在防止資料遺失的交易 ID 環繞保護措施。在此情況下使用單一使用者模式的唯一原因是,如果您希望 TRUNCATE
或 DROP
不需要的資料表,以避免需要 VACUUM
它們。三百萬筆交易的安全邊際的存在,是為了讓管理員能夠做到這一點。 有關使用單一使用者模式的詳細資訊,請參閱 postgres 參考頁面。
多重交易 ID 用於支援多個交易的資料列鎖定。由於 Tuple 標頭中用於儲存鎖定資訊的空間有限,因此只要有多個交易同時鎖定一個資料列,該資訊就會被編碼為「多重交易 ID」,簡稱為 multixact ID。有關任何特定 multixact ID 中包含哪些交易 ID 的資訊,會分別儲存在 pg_multixact
子目錄中,只有 multixact ID 會出現在 Tuple 標頭中的 xmax
欄位中。與交易 ID 一樣,multixact ID 以 32 位元計數器和相應儲存體的方式實現,所有這些都需要仔細的老化管理、儲存體清理和環繞處理。有一個單獨的儲存區域,用於保存每個 multixact 中的成員清單,該清單也使用 32 位元計數器,並且也必須進行管理。
每當 VACUUM
掃描資料表的任何部分時,它會將遇到的任何比 vacuum_multixact_freeze_min_age 更舊的 multixact ID 替換為不同的值,該值可以是零值、單個交易 ID 或較新的 multixact ID。對於每個資料表,pg_class
.relminmxid
儲存仍然出現在該資料表任何 Tuple 中的最舊 multixact ID。如果此值比 vacuum_multixact_freeze_table_age 更舊,則會強制執行激進的清理 (vacuum)。如前一節所述,激進的清理表示只會略過那些已知已完全凍結的頁面。mxid_age()
可用於 pg_class
.relminmxid
以查找其年齡。
無論是什麼原因導致,激進的 VACUUM
保證能夠推進資料表的 relminmxid
。最終,當所有資料庫中的所有資料表都被掃描並且它們最舊的 multixact 值被推進時,可以移除較舊 multixact 的磁碟儲存。
作為一種安全裝置,對於任何 multixact 年齡大於 autovacuum_multixact_freeze_max_age 的資料表,將會進行激進的清理掃描。此外,如果 multixact 成員佔用的儲存空間超過 2GB,則會更頻繁地對所有資料表進行激進的清理掃描,從那些具有最舊 multixact 年齡的資料表開始。即使名義上停用了自動清理,也會發生這兩種激進掃描。
與 XID 案例類似,如果自動清理無法從資料表中清除舊的 MXID,則當資料庫中最舊的 MXID 從環繞點達到四千萬筆交易時,系統將開始發出警告訊息。而且,就像 XID 案例一樣,如果忽略這些警告,一旦直到環繞剩餘的數量少於三百萬,系統將拒絕產生新的 MXID。
當 MXID 耗盡時,可以像 XID 耗盡時一樣恢復正常運作。請按照上一節中的相同步驟操作,但有以下差異
pg_stat_activity
;但是,尋找舊的 XID 仍然是確定哪些交易導致 MXID 環繞問題的好方法。PostgreSQL 有一個可選但強烈建議的功能,稱為自動清理,其目的是自動執行 VACUUM
和 ANALYZE
命令。啟用後,自動清理會檢查已插入、更新或刪除大量 Tuple 的資料表。這些檢查使用統計資訊收集工具;因此,除非將 track_counts 設定為 true
,否則無法使用自動清理。在預設配置中,已啟用自動清理,並且相關的配置參數已適當地設定。
「“自動清理精靈(autovacuum daemon)”」實際上是由多個處理程序所組成。 其中有一個持續運行的精靈處理程序,稱為自動清理啟動器(autovacuum launcher),負責為所有資料庫啟動自動清理工作者(autovacuum worker)處理程序。 啟動器會將工作分散到各個時間點,嘗試在每個資料庫中每隔autovacuum_naptime秒啟動一個工作者。 (因此,如果安裝包含N
個資料庫,則每autovacuum_naptime
/N
秒將啟動一個新的工作者。) 同時最多允許運行autovacuum_max_workers個工作者處理程序。 如果要處理的資料庫超過autovacuum_max_workers
個,則會在第一個工作者完成後立即處理下一個資料庫。 每個工作者處理程序都會檢查其資料庫中的每個表,並根據需要執行VACUUM
和/或ANALYZE
。log_autovacuum_min_duration可用於監控自動清理工作者的活動。
如果多個大型資料表在短時間內都符合清理的資格,則所有自動清理工作者可能會長時間忙於清理這些資料表。 這將導致其他資料表和資料庫在有工作者可用之前都無法進行清理。 對於單個資料庫中可以有多少個工作者沒有限制,但是工作者會嘗試避免重複其他工作者已經完成的工作。 請注意,正在運行的工作者數量不會計入max_connections或superuser_reserved_connections的限制中。
如果資料表的relfrozenxid
值早於autovacuum_freeze_max_age個交易,則始終會清理該資料表(這也適用於通過儲存參數修改凍結最大年齡的資料表;請參見下文)。 否則,如果自上次VACUUM
以來已過時的元組數超過了「“清理臨界值(vacuum threshold)”」,則清理該資料表。 清理臨界值的定義為
vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuples
其中清理基礎臨界值為autovacuum_vacuum_threshold,清理比例因子為autovacuum_vacuum_scale_factor,元組數為pg_class
.reltuples
。
如果在上次清理之後插入的元組數超過了定義的插入臨界值,也會清理該資料表,插入臨界值的定義為
vacuum insert threshold = vacuum base insert threshold + vacuum insert scale factor * number of tuples
其中清理插入基礎臨界值為autovacuum_vacuum_insert_threshold,清理插入比例因子為autovacuum_vacuum_insert_scale_factor。 這樣的清理可以將資料表的某些部分標記為全部可見(all visible),並允許凍結元組,從而減少後續清理所需的工作量。 對於接收INSERT
操作但沒有或幾乎沒有UPDATE
/DELETE
操作的資料表,降低資料表的autovacuum_freeze_min_age可能是有益的,因為這可以讓較早的清理凍結元組。 過時的元組數和插入的元組數是從累積統計系統中獲得的;它是一個最終一致的計數,由每個UPDATE
、DELETE
和INSERT
操作更新。 如果資料表的relfrozenxid
值早於vacuum_freeze_table_age
個交易,則會執行積極的清理來凍結舊元組並推進relfrozenxid
;否則,僅掃描自上次清理以來已修改的頁面。
對於分析(analyze),使用類似的條件:將臨界值(定義為
analyze threshold = analyze base threshold + analyze scale factor * number of tuples
與自上次ANALYZE
以來插入、更新或刪除的元組總數進行比較。
分割資料表不直接儲存元組,因此不會由自動清理處理。 (自動清理會像其他資料表一樣處理資料表分割區。) 不幸的是,這意味著自動清理不會在分割資料表上運行ANALYZE
,並且這可能會導致引用分割資料表統計資料的查詢產生次佳的計畫。 您可以通過在首次填充分割資料表時手動在分割資料表上運行ANALYZE
來解決此問題,並且在分割區中的資料分佈發生重大變化時再次運行。
自動清理無法存取暫存資料表。 因此,應通過會話SQL命令執行適當的清理和分析操作。
預設的臨界值和比例因子取自postgresql.conf
,但是可以覆蓋它們(以及許多其他自動清理控制參數),每個資料表都可以單獨設置;有關更多資訊,請參見儲存參數。 如果已通過資料表的儲存參數更改了設定,則在處理該資料表時使用該值;否則,使用全域設定。 有關全域設定的更多詳細資訊,請參見第 19.10 節。
當多個工作者正在運行時,自動清理成本延遲參數(請參見第 19.4.4 節)在所有正在運行的工作者之間“平衡”,因此對系統的總I/O影響是相同的,而與實際運行的工作者數量無關。 但是,在平衡演算法中不考慮任何處理資料表的儲存參數(每個資料表設定的autovacuum_vacuum_cost_delay
或autovacuum_vacuum_cost_limit
)的工作者。
自動清理工作者通常不會阻止其他命令。 如果處理程序嘗試獲取與自動清理持有的SHARE UPDATE EXCLUSIVE
鎖衝突的鎖,則獲取鎖會中斷自動清理。 有關衝突鎖定模式,請參見表 13.2。 但是,如果自動清理正在運行以防止交易ID迴繞(即,pg_stat_activity
視圖中的自動清理查詢名稱以(to prevent wraparound)
結尾),則不會自動中斷自動清理。
定期運行獲取與SHARE UPDATE EXCLUSIVE
鎖衝突的鎖的命令(例如ANALYZE)可能會有效地阻止自動清理完成。
如果您在文件中發現任何不正確的地方,與您特定功能的體驗不符,或需要進一步澄清的地方,請使用此表單回報文件問題。