天天看點

PostgreSQL存儲空間回收

随着資料庫的運作,存儲空間裡會産生一些無用的資料,需要進行清理。

産生這些無用資料的原因有:

? 行被删除

? 插入行的事務終止

? 由更新産生的舊的行版本

需要回收的存儲空間主要包括以下幾個方面:

? 行版本(占用空間最大)

? 行版本指針(占用空間最小)

? 索引項

通過SELECT,UPDATE和DELETE通路表時,會觸發表的單頁清理。清理對象僅限于被廢棄的行版本(對任何事務都不可見)。同時标記行版本指針為Dead狀态。下次執行vacuum時,會回收不用的索引項和行版本指針。

删除前: 

PostgreSQL存儲空間回收

删除後:

PostgreSQL存儲空間回收

*)行版本指針共有4個狀态,存儲在lp_flags域:

Unused

Normal

Redirect

Dead

通過vacuum或autovacuum清理時,被廢棄的行版本,行版本指針和索引項都會得到清理。普通的vacuum不會釋放存儲空間給OS,除非在表檔案的末尾有連續的空頁。vacuum full會将整個資料重寫一遍,僅保留有用的資料。vacuum full時要鎖住整個表,會影響其它并發作業。

vacuum後:

PostgreSQL存儲空間回收

滿足以下條件時,采用稱之為HOT(heap-only tuples)更新的技術提高性能。

1)新舊行版本存儲在同一個頁上

2)更新不涉及被索引列值的變更

通過行版本頭部的ctid或者行版本指針的lp_flags(Redirect)+lp_off讓舊版本指向新版本,形成一個HOT更新鍊。這樣在更新時就可以重用原來的索引項,避免删除和追加索引項。索引項仍然指向舊的行版本指針,然後通過HOT更新鍊找到對應的新版本。

使用ctid或lp_flags(Redirect)+lp_off形成HOT更新鍊的差別在于:前者保留了舊的行版本,而後者用于舊的行版本已被回收的情況。當舊的行版本對某些活動事務仍然可見時,是不能被回收的。HOT更新時對于處于HOT更新鍊中間位置的行版本指針是可以被立即回收的(頭指針被索引使用,尾指針指向最新的行版本,是以要保留)。

初始狀态:隻有一個版本

PostgreSQL存儲空間回收

第一次更新:通過舊行版本頭部的ctid指向新行班本

PostgreSQL存儲空間回收

第二次更新:V1的行版本空間被再利用。并且通過Redirect将索引使用的第一個行版本指針引向保留下來的最老的行版本。

PostgreSQL存儲空間回收

第三次更新:

PostgreSQL存儲空間回收

最終由于其他操作觸發廢棄的行版本被回收:

PostgreSQL存儲空間回收

為了能讓HOT更新充分發揮作用,需要盡量減少不必要的索引,并合理設定表的存儲參數fillfactor。

fillfactor控制插入時頁存儲空間的使用率,取值範圍為10%~100%,預設值為100,即不為HOT更新保留白間。

對于頻繁更新非索引列的表,應該将fillfactor适當設小。

<a href="http://momjian.us/main/writings/pgsql/mvcc.pdf">http://momjian.us/main/writings/pgsql/mvcc.pdf</a>