評估及解決資料表和索引膨脹問題

如果清除作業無法跟上資料操縱語言 (DML) 對資料表執行的速率,就會發生資料表和索引膨脹的情況。部分表格和索引膨脹是無可避免的,一般來說可以接受,因為交易可以重複使用該空間。嚴重膨脹會導致效能問題,例如查詢時間變慢、I/O 增加、共用緩衝區和快取使用效率降低,以及儲存空間成本增加。

如要估算膨脹程度,最好的方法是使用 pgstattuple 模組。不過,如果擴充功能必須讀取關係的所有頁面,使用 pgstattuple 的效率就會較低。如果無法使用 pgstattuple,可以改用其他指令碼估算膨脹,但這種做法的準確度較低。

讀取 pgstattuple 輸出內容

使用 pgstattuple 回報表格或索引的實體儲存特性時,輸出內容的格式如下:

> SELECT * FROM pgstattuple('large_table');
-[ RECORD 1 ]------+-----------
table_len          | 7431888896
tuple_count        | 66666666
tuple_len          | 2796296271
tuple_percent      | 37.63
dead_tuple_count   | 0
dead_tuple_len     | 0
dead_tuple_percent | 0
free_space         | 3873153652
free_percent       | 52.12

輸出內容說明如下:

table_len (7431888896)
資料表總大小 (以位元組為單位)。包括所有有效元組、無效元組和可用空間。在本例中,large_table約佔 7,088 GB。
tuple_count (66666666)
代表資料表中的有效元組數量,也就是可見且有效的資料列。這個資料表包含約 6,600 萬個有效列。
tuple_len (2796296271)
所有即時元組的總長度 (以位元組為單位),約為 2.6 GB。
tuple_percent (37.63)

有效元組占用的 table_len 百分比。計算方式如下:

(tuple_len/table_len) ∗ 100 = (2796296271/7431888896) ∗ 100 ≈ 37.63 百分比

這項輸出內容表示有效資料使用的磁碟空間不到資料表的 40%。

dead_tuple_count (0)

無效元組的數量,也就是更新或刪除後,真空作業尚未移除的資料列。0 值表示資料表已清除,沒有待回收的無效元組。這通常表示 VACUUM 或 autovacuum 在資料表上有效率地執行。

dead_tuple_len (0)

所有無效元組的總長度 (以位元組為單位)。與 dead_tuple_count 一致,0 值表示無效資料列不會耗用任何空間。

dead_tuple_percent (0)

無效元組占用的 table_len 百分比。計算方式如下:

(dead_tuple_len/table_len) ∗ 100 = (0/7431888896) ∗ 100 = 0%

free_space (3873153652)

這個值代表資料表資料頁面中的可用空間量。您可以重複使用這個空間來插入或更新資料,不必擴充表格。這表示有大量可用空間,約為 3.7 GB。

free_percent (52.12)

這個值代表 table_len 的可用空間百分比。 計算方式如下:

(free_space/table_len) ∗ 100 = (3873153652/7431888896) ∗ 100 ≈ 52.12%

使用查詢估算膨脹

您可以對系統目錄表執行查詢來估算膨脹,但這種方法的準確度不如使用 pgstattuple 等擴充功能。如果您使用 PostgreSQL 資料表膨脹檢查等指令碼,資料表統計資料必須為最新狀態,否則估算結果會不準確。

將查詢的輸出內容與 pgstattuple 模組進行比較時,估計值具有可比性,但並非膨脹的確切測量結果。不過,由於 SQL 查詢依賴 PostgreSQL 的累計統計資料引擎,而模組會讀取實際資料頁面,因此模組仍是更準確的膨脹指標。

以下範例比較兩種不同方法的輸出內容,這兩種方法用於分析 PostgreSQL 中名為 large_table 的資料表膨脹。

> SELECT * FROM pgstattuple('large_table');
-[ RECORD 1 ]------+-----------
table_len          | 2475892736
tuple_count        | 22000000
tuple_len          | 922925931
tuple_percent      | 37.28
dead_tuple_count   | 0
dead_tuple_len     | 0
dead_tuple_percent | 0
free_space         | 1293696900
free_percent       | 52.25

Vs.

-[ RECORD 1 ]+------------
databasename | postgres
schemaname   | public
tablename    | large_table
can_estimate | t
est_rows     | 21965400
pct_bloat    | 54
mb_bloat     | 1269.24
table_mb     | 2361.195

地址膨脹

您可以透過下列方式管理膨脹,每種方式都有優缺點,因此需要仔細規劃:

  • 徹底吸塵。這項作業需要完整鎖定資料表,時間長度為清除作業的持續時間,且需要停機。
  • 將資料移至新資料表。如要使用這個方法,您必須暫停表格變更,確保變更不會轉移至新關係。
  • 請使用 pg_squeeze。這項擴充功能可減少線上膨脹。擴充功能會建立影子資料表、插入所有資料,然後使用複製位置維護資料表變更,直到最後一個步驟為止,也就是將膨脹的資料表換成新建立的非膨脹資料表。然後要求短暫鎖定資料表,將非膨脹資料表移至膨脹資料表的位置,取代膨脹資料表。這個方法在作業期間需要兩倍的物件空間,但對正常作業的干擾最少。