跳至主要内容

PostgreSQL Vacuum 操作

PostgreSQL 在更新或刪除資料時會產生 dead tuples。
Vacuum 主要負責回收 dead tuples 所佔用的磁碟空間,並更新查詢策略 (Query Planner) 所需的統計資訊。
以提升資料庫效能,並降低磁碟佔用空間。

  • PostgreSQL 在 8.1 版後開始提供自動執行空間清理與回收機制 (autovacuum)。

Dead Tuples (死亡元組)

可想成是 windows 用久了之後,會造成磁區髒亂。而 PostgreSQL Vacuum 就是 Windows 的磁碟重整。
dead tuples 可簡單說成是暫時被 PostgreSQL 這清潔人員標記 '已退房,待清潔' 的旅館房間。
Vacuum 就是清潔人員打掃動作。
打掃完回報櫃台,櫃台重新統計空房數與位置便是 VACUUM ANALYZE。

手動 Vacuum 時機

  • 資料庫統計資訊嚴重失真 :
    • Rows (counted)與 Rows (estimated) 差異太大。影響資料庫的查詢策略 (Query Planner) 與效能。
    • 使用 VACUUM ANALYZE 指令更新統計值
  • 大量資料變動後 :
    • 當資料表經歷了大量的 UPDATEDELETE 操作後,會產生許多 dead tuples。
  • 大量資料載入後 :
    • 載入後應馬上執行 VACUUM ANALYZE 立即更新統計資訊。
  • Temp Tables :
    • autovacuum 通常無法存取和清理 Temp Tables 而造成磁碟混亂。
  • autovacuum 無法及時處理 : 離峰時增加人工觸發。
    • 資料庫交易頻繁時 autovacuum 被延後觸發。
  • 排程或空間衝突 :
    • 空間不足: 指的是將被標記可重用的空間還給作業系統。這是硬碟空間不足時的緊急應變措施。與 DB 效能較無關。
    • 時間衝突: autovacuum 與使用者使用高峰期相衝突,而被暫緩觸發或終止。

Vacuum 語法: Table vacuum

  • 參考來源
  • option 包含下列:
    • FULL : 重謄資料,完全鎖定造成 DB 無法使用
    • ANALYZE : 更新 Query Planner 統計資訊
    • VERBOSE : 輸出詳細的清理活動報告
    • PARALLEL (這個 opt 填數值)
    • FREEZE : 避免交易 ID 因溢位被重複使用。預設啟用。
    • 其他: DISABLE_PAGE_SKIPPING,SKIP_LOCKED,INDEX_CLEANUP,TRUNCATE
-- syntax
VACUUM [ ( option [, ...] ) ] [ table_and_columns [, ...] ]

-- example
VACUUM (VERBOSE, ANALYZE) table_insect_totem;

Vacuum 語法: Database vacuumdb

  • 下列指令是對 database 所有的 table 做 vacuum 與 analyze,不會造成 table lock
  • 參數
    • -U: Role
    • -d: database 名稱
-- syntax
vacuumdb -h localhost -U roleUser -d databaseName -v -z

指令

  • 在不造成資料庫鎖定前提下,一般常用的是:
    • VACUUM : 回收 dead tuples
    • VACUUM (VERBOSE, ANALYZE) : 回收 dead tuples,並統計分析
指令主要功能鎖定層級
(Lock Level)
歸還空間給 OS效能使用時機
VACUUM回收 dead tuples 佔用的空間無鎖定,不會阻擋 DML
(SELECT/INSERT/UPDATE/DELETE)
輕微 I/O日常手動維護、大量資料刪改後
VACUUM FULLTable 重謄資料,徹底移除未使用空間排他,會阻擋所有讀寫操作大量 I/O+CPU必需縮小檔案大小時,應於離峰時維護用
ANALYZEQuery Planner 所需統計資訊更新不影響 SELECT,
但會阻擋 DDL 和其他 VACUUM
少量讀取和 CPU 計算查詢效能下降、執行計畫不佳時、大量資料載入後
VACUUM ANALYZEVACUUM + ANALYZE無鎖定少量 I/O日常手動維護指令
VACUUM (VERBOSE)VACUUM + 附加輸出過程NANANA用於了解 VACUUM 的過程

預設 Auto Vacuum 時機

auto 並非意味著定期值行,
而是 autovacuum launcher 於背景檢查相關參數,
當滿足 Vacuum 條件時才啟動另一個 worker 執行實際動作。
條件指的是 Table 發生變動的程度
也就是過期或異動過的資料量達到設定時才滿足。
autovacuum 主要執行的動作是 VACUUM ANALYZE
相關預設參數設置於 postgresql.conf 檔案中

VACUUM (空間回收) 動作相關參數

  • Vacuum 主要是做 回收無效資料佔用的空間
    • autovacuum_vacuum_threshold : 預設 50,dead tuples 多於 50 就滿足基本條件。
    • autovacuum_vacuum_scale_factor : 預設 0.2 (20%),dead tuples 大於資料的百分之 20。所以 Table 內容越多,觸發週期可能越久。

VACUUM 驅動條件

    死亡元組數 (dead tuples) > autovacuum_vacuum_threshold + (autovacuum_vacuum_scale_factor × 資料表總行數)

ANALYZE (統計資訊更新)動作關參數

  • Analyze 主要是做 統計資訊更新 ,以供 Query Planner 做決策參考。
    • autovacuum_analyze_threshold : 預設 50,資料異動的筆數多於 50 就滿足基本條件。
    • autovacuum_analyze_scale_factor : 預設 0.1 (10%),資料異動筆數大於資料的百分之 10。

ANALYZE 驅動條件

    被 Insert、Update 或 Delete 的 Tuples 總數 > autovacuum_analyze_threshold + (autovacuum_analyze_scale_factor × 資料表總行數)

autovacuum 面臨的瓶頸

  • autovacuum,目的在將對系統效能的影響降到最低。
  • 對於資料量非常大的 Table,或是 update / delete 頻繁的 Table,採用百分比設定可能會導致 autovacuum 不夠頻繁,與空間佔用過多 (bloat) 而使得查詢效能下降。
  • 針對大型或高頻變動資料表,資料庫管理員(DBA) 可調低 autovacuum_vacuum_scale_factorautovacuum_analyze_scale_factor 的值,讓 autovacuum 提早發生。

VACUUM ANALYZE 參數調整: Alter Table

  • 下面介紹針對單一 Table 處理
  • 若需調整全域設定之接改 postgresql.conf 即可

針對對單一 Table 調整參數

-- syntax
ALTER TABLE table_name SET (target_parameter = value, ...);

-- 回復全域預設值 (by Set or Reset)
ALTER TABLE table_name SET (target_parameter = NULL);
ALTER TABLE table_name RESET (target_parameter, ...);

-- example
ALTER TABLE event_logs SET (
autovacuum_vacuum_scale_factor = 0.02,
autovacuum_analyze_scale_factor = 0.01
);

恢復預設值

-- 使用 RESET,推薦
ALTER TABLE event_logs RESET (autovacuum_vacuum_scale_factor, autovacuum_analyze_scale_factor);

-- 將值設為 null 也能達到相同效果
ALTER TABLE event_logs SET (
autovacuum_vacuum_scale_factor = NULL,
autovacuum_analyze_scale_factor = NULL
);

查詢參數設定值

  • pg_class : 確認特定資料表的客製化設定
  • relname : 填入 table name
  • reloptions : 陣列形式呈現這些設定
  • 若回傳 null 代表採用全域設定
    SELECT relname, reloptions FROM pg_class WHERE relname = 'event_logs';

查詢 Vacuum 紀錄

  • 此範例將多資訊整成一張表
    SELECT psut.relname,
to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') as last_vacuum,
to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') as last_autovacuum,
to_char(psut.last_analyze, 'YYYY-MM-DD HH24:MI') as last_analyze,
to_char(psut.last_autoanalyze, 'YYYY-MM-DD HH24:MI') as last_autoanalyze,
to_char(pg_class.reltuples, '9G999G999G999') AS n_tup, --row count
to_char(psut.n_dead_tup, '9G999G999G999') AS dead_tup, --delete count, can reuse
to_char(CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
+ (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
* pg_class.reltuples), '9G999G999G999') AS av_threshold,
CASE
WHEN CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
+ (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
* pg_class.reltuples) < psut.n_dead_tup
THEN '*'
ELSE ''
END AS expect_av
FROM pg_stat_user_tables psut
JOIN pg_class on psut.relid = pg_class.oid
ORDER BY pg_class.reltuples desc;