眾所周知,在PostgreSQL里面使用VACUUM FULL來回收dead tuples空間並將其返回給操作系統。但是我執行VACUUM FULL卻沒有任何效果,是數據庫版本出現了bug?當然不是!
經排查原來是Physical Replication Slot導致(具體解釋見http://mysql.taobao.org/monthly/2015/02/03/)。將hot_standby_feedback設為on時,從庫關閉,主庫的xmin不再改變,主庫的vaccum操作停滯,造成主庫被頻繁更新的表大小暴增。
為什么VACUUM不清理死元組
?
VACUUM
只能刪除不再需要的那些行版本(也稱為“元組”)。如果刪除事務的事務 ID(存儲在xmax
中)早於 PostgreSQL 數據庫(或共享表的整個集群)中仍處於活動狀態的最舊事務,則無法清除元組。
在 PostgreSQL 集群中,有三件事可以阻止這個VACUUM回收死元組:
-
長時間運行的事務:
可以通過以下查詢找到長時間運行的事務及其xmin值:
SELECT pid, datname, usename, state, backend_xmin FROM pg_stat_activity WHERE backend_xmin IS NOT NULL ORDER BY age(backend_xmin) DESC;
可以使用該
pg_terminate_backend()
函數來終止阻止您的VACUUM
. -
廢棄的Replication Slot:
復制槽是一種數據結構,保持從主庫丟棄但仍需要由備用服務器趕上主要信息PostgreSQL服務器的數據。
如果復制延遲或備用服務器關閉,復制槽將阻止
VACUUM
刪除舊行。可以使用此查詢找到所有復制槽及其xmin值:
SELECT slot_name, slot_type, database, xmin FROM pg_replication_slots ORDER BY age(xmin) DESC;
使用該
pg_drop_replication_slot()
函數刪除不再需要的復制槽。注意:如果
hot_standby_feedback = on
. 對於邏輯復制存在類似的危險(無法回收元組),但只有系統目錄受到影響。catalog_xmin
在這種情況下檢查列。 -
孤立的准備運行的事務:
在兩階段提交期間,分布式事務首先用
PREPARE
語句准備,然后用COMMIT PREPARED
語句提交。一旦一個事務准備好,它就會一直“等待”直到它被提交或中止。它甚至必須在服務器重啟后還需要保留下來!通常,事務不會長時間保持准備狀態,但有時會出錯,必須由管理員手動刪除准備好的事務。
可以
xmin
使用以下查詢找到所有准備好的交易及其價值:SELECT gid, prepared, owner, database, transaction AS xmin FROM pg_prepared_xacts ORDER BY age(transaction) DESC;
使用
ROLLBACK PREPARED
SQL 語句刪除准備好的事務。