pg_squeeze(資料表空間整理)

更新時間:
Copy as MD

當表因頻繁的UPDATEDELETE操作產生大量片段(即表膨脹)時,會導致儲存空間浪費和查詢效能下降。pg_squeeze外掛程式通過線上重組表的方式自動回收這些膨脹空間。它基於邏輯解碼捕獲資料變更,對業務寫入效能影響很小,且完全在服務端自動運行,協助您在不中斷業務的前提下,持續最佳化表結構,提升資料庫效能與空間利用率。

適用範圍

支援的PolarDB PostgreSQL版(相容Oracle)的版本: Oracle文法相容 2.0,且核心小版本需為2.0.14.19.40.0及以上。

說明

您可在控制台查看核心小版本號碼,也可以通過SHOW polardb_version;語句查看。如未滿足核心小版本要求,請升級核心小版本

pg_repack對比

pg_squeezepg_repack功能相似,都是用於處理表膨脹問題的常用擴充。pg_squeeze作為pg_repack的替代方案,在實現原理和營運方式上存在差異,可根據業務情境選擇。

對比項

pg_squeeze

pg_repack

實現原理

邏輯解碼(Replication Slot):通過複製槽非同步捕獲WAL中的資料變更。

觸發器(Trigger):在源表上建立觸發器,同步捕獲DML操作。

對業務寫入影響

較小。變更捕獲是非同步過程,對源表寫入效能影響有限。

較大。每次DML操作都會額外觸發一次寫入,在高並發下可能成為效能瓶頸。

資源消耗

消耗一個複製槽。若壓縮任務處理緩慢或失敗,可能導致WAL日誌堆積,佔用儲存空間。

觸發器在高並發下會增加CPU開銷。需要額外的日誌表記錄變更。

營運複雜度

需關注複製槽狀態和WAL儲存空間,防止因任務異常導致磁碟寫滿。

需關注觸發器本身的管理,確保其在表結構變更或資料移轉後仍能正常工作。

快速入門

本節將引導您完成從安裝配置到成功啟用一個表的自動壓縮任務的全過程。

步驟一:配置叢集參數

  1. 登入PolarDB控制台,在集群列表頁面找到目的地組群,單擊叢集ID進入詳情頁。

  2. 在左側導覽列選擇配置与管理 > 参数配置

  3. 参数配置頁面,修改以下參數:

    • wal_level:設定為logical。這是使用邏輯解碼功能的前提,會適度增加WAL日誌的產生量。

    • max_replication_slots:確保有足夠餘量。pg_squeeze在每個啟用的資料庫中至少需要1 + squeeze.workers_per_database個複製槽。建議設定為比當前值至少大2的值(例如,從10調整到12)。

    • shared_preload_libraries:在現有值的基礎上追加,pg_squeeze。例如,如果原值為pg_stat_statements,則修改為pg_stat_statements,pg_squeeze

  4. 等待叢集重啟後參數配置生效。

步驟二:安裝外掛程式並啟動後台進程

在需要進行資料表空間整理的目標資料庫中啟用pg_squeeze功能。

  1. 登入至目標資料庫。

  2. 執行以下SQL語句,建立外掛程式並啟動後台調度背景工作處理序(Scheduler Worker)。該進程會根據squeeze.tables中的配置,定時檢查並建立壓縮任務。

    -- 在目標資料庫中建立擴充
    CREATE EXTENSION pg_squeeze;
    
    -- 啟動後台調度進程
    -- 此操作只需在每個需要使用pg_squeeze的資料庫中執行一次
    SELECT squeeze.start_worker();
  3. (可選)執行以下SQL語句,驗證後台進程是否成功啟動。如果看到application_namesqueeze scheduler的進程,則表示啟動成功。

    SELECT * FROM pg_stat_activity WHERE application_name LIKE 'squeeze%';

步驟三:配置待處理的表

告知pg_squeeze需要管理哪些表,以及按何種策略進行檢查和壓縮。

  1. 確保表具備REPLICA IDENTITY(副本標識)pg_squeeze需要通過唯一標識來匹配新舊錶中的行變更。通常,主鍵(Primary Key)會自動作為REPLICA IDENTITY

    • 檢查:使用\d+ your_table_name命令查看錶的Replica identity屬性是否為DEFAULTFULL

    • 設定:如果表沒有主鍵,但有一個唯一索引(例如your_table_uidx),可執行以下命令將其設定為REPLICA IDENTITY

      ALTER TABLE your_table_name REPLICA IDENTITY USING INDEX your_table_uidx;
  2. 將表註冊到squeeze.tables將表資訊及調度策略插入squeeze.tables配置表中。schedule欄位用於定義檢查時間,其格式類似於Cron運算式。

    -- 樣本1:每天淩晨2:30檢查public.foo表
    INSERT INTO squeeze.tables (tabschema, tabname, schedule)
    VALUES ('public', 'foo', ROW(ARRAY[30], ARRAY[2], NULL, NULL, NULL)::squeeze.schedule);
    
    -- 樣本2:每周日淩晨4:00檢查public.bar表,並指定壓縮後按主鍵排序
    INSERT INTO squeeze.tables (tabschema, tabname, schedule, clustering_index)
    VALUES ('public', 'bar', ROW(ARRAY[0], ARRAY[4], NULL, NULL, ARRAY[0])::squeeze.schedule, 'bar_pkey');

    schedule欄位的結構為(分鐘, 小時, 日, 月, 星期)NULL表示任意時間。更多配置請參見附錄:squeeze.tables配置表詳解

步驟四:監控與驗證

確認壓縮任務是否按預期執行、成功或失敗。您可以通過查詢pg_squeeze提供的視圖和表來監控任務狀態。

-- 查看當前資料庫中進行中的壓縮任務
SELECT * FROM squeeze.get_active_workers();

-- 查看最近10條成功的壓縮記錄
SELECT * FROM squeeze.log ORDER BY finished DESC LIMIT 10;

-- 查看失敗的壓縮記錄及原因
SELECT * FROM squeeze.errors;

步驟五:(可選)取消定製壓縮

如果特定表不再需要定期壓縮,只需從squeeze.tables表中刪除相應的行即可。

DELETE FROM squeeze.tables WHERE tabschema = 'public' AND tabname = 'foo';

手動觸發即時壓縮

除了按計劃自動執行,您也可以手動觸發對任意表的即時壓縮,而無需將其註冊到squeeze.tables中。對特定表進行一次性的、立即執行的壓縮操作。

使用squeeze.squeeze_table()函數發起一個手動壓縮任務。

-- 對 public.pgbench_accounts 表發起一次預設的壓縮任務
SELECT squeeze.squeeze_table('public', 'pgbench_accounts');

-- 發起壓縮任務,並指定壓縮後按主鍵(pgbench_accounts_pkey)進行物理排序
SELECT squeeze.squeeze_table('public', 'pgbench_accounts', 'pgbench_accounts_pkey');
說明

squeeze.squeeze_table函數不是事務性的。它僅負責啟動一個後台背景工作處理序來執行壓縮,然後立即返回。復原調用該函數的事務,並不會中止已經啟動的後台壓縮任務。

配置進階選項

調整並發與鎖行為

在不影響業務的前提下,更精細地控制壓縮過程。通過設定squeeze.max_xlock_time參數,可以限制壓縮最後階段獨佔鎖定的最長持有時間,避免長時間阻塞業務。

-- 設定獨佔鎖定最長持有時間為100毫秒
SET squeeze.max_xlock_time TO 100;

如果鎖持有時間超過此限制,pg_squeeze會釋放鎖,處理在此期間發生的資料變更,然後再次嘗試擷取鎖。若多次嘗試均逾時,任務將報錯中止。如果頻繁發生鎖逾時失敗,應優先考慮將任務調度到業務負載更低的時間視窗,其次再考慮適當增大此參數值。

配置並發背景工作處理序數

當需要同時處理的表較多時,通過增加背景工作處理序數來提高壓縮效率。您可以將squeeze.workers_per_database參數設定為大於1的值,以允許在單個資料庫中平行處理多個表的壓縮任務。

-- 允許每個資料庫最多同時運行2個壓縮背景工作處理序
SET squeeze.workers_per_database = 2;
說明

此設定會影響所有正在使用pg_squeeze外掛程式的資料庫。叢集中所有Workers(包括Scheduler Worker)的總數不能超過參數max_worker_processes的數值。

附錄:squeeze.tables配置表詳解

squeeze.tablespg_squeeze的核心配置表,您通過向此表插入記錄來註冊需要管理的表並定義其處理策略。

欄位

類型

描述

預設值

配置建議

tabschema

name

表所在的模式名。

-

-

tabname

name

表名。

-

-

schedule

squeeze.schedule

任務檢查調度時間,格式為(分鐘, 小時, 日, 月, 星期)

-

根據業務低峰期設定。例如,每天淩晨2:30執行:ROW(ARRAY[30], ARRAY[2], NULL, NULL, NULL)::squeeze.schedule

free_space_extra

integer

觸發壓縮所需的額外膨脹空間百分比(超出fillfactor預留空間之外的部分)。

50

對於寫入頻繁的OLTP表,可適當調低此值(如30),以更頻繁、小批量地回收空間。

min_size

integer

表佔用的最小儲存空間(MB),小於此值的表不會被處理。

8

保持預設值即可,避免對小表進行不必要的操作。

vacuum_max_age

interval

自上次VACUUM後,空閑空間映射(FSM)被認為有效最長時間。

'1 hour'

保持預設值。若超過此時間,pg_squeeze會進行更深入的分析來判斷是否需要壓縮。

max_retry

integer

當首次壓縮失敗時,允許的最大重試次數。

0

如果表經常因DDL變更等原因導致壓縮失敗,可適當增加此值(如2),以提高任務成功率。

clustering_index

name

指定一個現有索引,壓縮完成後表內資料將按此索引的索引值進行物理排序,效果類似CLUSTER命令。

NULL

對於範圍查詢頻繁的表,建議將其主鍵或核心查詢索引作為分區鍵,可顯著提升查詢效能。

rel_tablespace

name

指定壓縮後表要遷移到的目標資料表空間。

NULL

用於資料表空間遷移情境。若為NULL,表將保留在原資料表空間。

ind_tablespaces

name[]

二維數組,用於指定索引的資料表空間映射。

NULL

用於索引的資料表空間遷移。

skip_analyze

boolean

是否在壓縮完成後跳過ANALYZE命令。

false

建議保持false。壓縮會改變表的資料分布,執行ANALYZE有助於最佳化器產生準確的執行計畫。