全部產品
Search
文件中心

PolarDB:pg_repack(儲存空間整理)

更新時間:Oct 24, 2024

PolarDB PostgreSQL版(相容Oracle)支援通過pg_repack外掛程式對錶空間進行重新“封裝”,回收片段空間,有效解決因對錶大量更新、刪除等操作引起的空間膨脹問題。pg_repack擷取排它鎖的時間較短,多數時間不阻塞讀寫,相比CLUSTER或VACUUM FULL操作更加輕量化。

前提條件

支援pg_repack外掛程式的PolarDB PostgreSQL版(相容Oracle)的版本如下:

資料庫引擎版本為Oracle文法相容 2.0,且核心小版本需為2.0.14.22.0及以上。

說明

您可通過如下語句查看PolarDB PostgreSQL版(相容Oracle)的核心小版本號碼:

SHOW polar_version; 

注意事項

  • 不支援使用-a/--all選項repack所有的資料庫。

  • 不支援repack整個資料庫,必須通過--table/--parent-table/--index選項指定需要repack的表或者索引。

  • 不支援使用-c/--schema選項repack整個schema。

  • 不支援使用-s/--tablespace指定的資料表空間,因為PolarDB PostgreSQL版(相容Oracle)不支援您直接建立資料表空間,而是使用預設的資料表空間。

  • pg_repack需要臨時佔用額外的儲存空間來儲存新表和日誌表,因此叢集剩餘儲存空間大小至少應為repack表大小的兩倍。

  • pg_repack會佔用較大的磁碟I/O,使用前請評估是否會影響業務。以PL1層級的ESSD雲端硬碟為例,對一個100 GB的表進行repack時會達到I/O吞吐上限(250 MB/s)。

使用方法

pg_repack作為安裝在PolarDB PostgreSQL版(相容Oracle)側的外掛程式作為服務端,並提供專用的用戶端給使用者,兩者需要搭配使用。

安裝外掛程式

CREATE EXTENSION pg_repack;

查看外掛程式版本。

SELECT extversion FROM pg_extension WHERE extname = 'pg_repack';

如果已經安裝了老版本外掛程式,可以通過先卸載原有外掛程式再重新建立的方式升級到最新版。

DROP EXTENSION pg_repack;
CREATE EXTENSION pg_repack;
說明

如果服務端沒有安裝pg_repack外掛程式,直接運行pg_repack命令用戶端會報錯:ERROR:pg_repack failed with error: pg_repack x.x.x is not installed in the database

安裝用戶端

pg_repack用戶端工具隨PolarDB-Tools工具包發布,下載安裝PolarDB-Tools後即可使用其中的pg_repack用戶端。下載地址及安裝方法請參見PolarDB-Tools

說明
  • pg_repack用戶端的版本必須匹配pg_repack外掛程式的版本,否則執行用戶端會報錯:ERROR:pg_repack failed with error: extension 'pg_repack x.x.x' required, found 'pg_repack y.y.y'; please drop and re-create the extensionERROR:pg_repack failed with error: program 'pg_repack x.x.x' does not match database library 'pg_repack y.y.y'

  • 請從上述連結中選擇與PolarDB叢集版本相匹配的PolarDB-Tools工具包進行下載和使用。

Repack普通表和分區表分區

pg_repack支援對普通表或者分區表的某個分區進行repack,其作用類似於CLUSTERVACUUM FULL操作,清理表中多餘的空閑空間,同時重建表上的索引,適用於資料表空間膨脹的情境

說明
  • repack表必須有主鍵或唯一索引。

  • 不支援對暫存資料表進行repack操作。

  • 不支援對帶有Global Index的分區進行repack操作。

文法說明一

  • 通過--table參數指定表名,預設情況下效果等同於CLUSTER,repack過程中對之前執行過CLUSTER操作的列進行排序:

    pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --table schema1.table1
  • 如果希望對指定的列進行排序,可以使用--order-by參數來指定列名:

    pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --table schema1.table1 --order-by <列名>
  • 如果不希望進行排序,即希望pg_repack的效果等同於VACUUM FULL,可以使用--no-order參數:

    pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --table schema1.table1 --no-order
  • 如果資料庫叢集的CPU和I/O資源充裕,可以使用--jobs參數加速repack操作,它會啟動多個進程並發重建索引,適用於表上有多個索引的情境:

    pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --table schema1.table1 --jobs <並發數量>

Repack分區表和繼承表

pg_repack支援對分區表(包括聲明式分區表和繼承式分區表)進行操作,它會自動找到父表的所有分區,並對每個分區依次進行repack操作。適用於分區表的所有分區都存在空間膨脹的情境

文法說明

  • 通過--parent-table參數指定分區表的表名

    pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --parent-table schema1.table1
    說明
    • 除了--parent-table參數以外,分區表的其他參數用法與普通表基本相同。

    • 如果只是單個分區存在空間膨脹,則無需對整個分區表進行repack,使用文法說明一中(--table參數)對單個分區進行repack操作即可。

    • 不支援對帶有Global Index的分區表進行repack操作。

Repack索引

pg_repack支援僅對索引進行repack操作,它的作用是重建索引,清理索引中的空閑空間,適用於索引空間膨脹的情境

說明
  • 如果索引空閑空間過多,推薦使用REINDEX CONCURRENTLY進行線上索引重建,無需使用pg_repack。pg_repack支援該能力的原因是老版本的PostgreSQL不支援REINDEX CONCURRENTLY,從而只能藉助pg_repack來實現。

  • 由於pg_repack社區的特性,暫不支援對聲明式分區表進行repack索引的操作,同樣可以使用REINDEX CONCURRENTLY來代替。

文法說明

  • 使用--index參數指定需要repack的索引名:

    pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --index schema1.table1
  • 使用--only-indexes參數repack表上的所有索引:

    pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --table schema1.table1 --only-indexes

更多用法

使用pg_repack --help可以查看pg_repack的更多用法。

常見問題

Dry Run

正式執行pg_repack之前建議使用--dry-run選項運行一次,該選項不動作表中的資料,僅驗證命令是否合法、流程是否可以跑通。待命令驗證成功後,再去掉該選項正式運行pg_repack。

pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --echo --table schema1.table1 --dry-run

許可權問題

  • 必須使用高許可權帳號運行pg_repack,不能以普通帳號身份運行,否則會報錯:must be polar_superuser or superuser to use xx function

  • 如果遇到You must be a superuser to use pg_repack報錯,則需要在pg_repack命令中增加--no-superuser-check選項來繞過超級使用者檢查。

逾時問題

如果需要repack的表或索引過大,repack過程耗時過長,則可能遇到FATAL: terminating connection due to idle-in-transaction timeoutFATAL: terminating connection due to idle-session timeout之類的錯誤。這表示pg_repack用戶端與PolarDB PostgreSQL版(相容Oracle)叢集的串連因為逾時而斷開,本次repack失敗。

解決方案是在pg_repack命令之前增加PGOPTIONS選項設定逾時相關參數來關閉逾時功能,以防止逾時導致串連斷開。

PGOPTIONS="-c idle_session_timeout=0 -c idle_in_transaction_session_timeout=0 -c statement_timeout=0" pg_repack -h <host> -p <port> -d <db> -U <user> --no-superuser-check --table schema1.table1

殘留對象清理

如果pg_repack在執行過程中異常退出,則repack失敗,被repack的表上可能殘留了repack過程中建立的對象,需要及時清理,否則可能影響表的使用:

  • 被repack的表上可能殘留repack_trigger觸發器,需要使用DROP TRIGGER命令刪除。

  • 被repack的表上可能殘留臨時索引index_<oid>,需要使用DROP INDEX CONCURRENTLY命令刪除。

  • repack模式下殘留暫存資料表repack_<oid>與日誌表log_<oid>,需要使用DROP TABLE命令刪除。

  • repack模式下殘留新的類型pk_<oid>,需要使用DROP TYPE命令刪除。

原理介紹

pg_repack外掛程式支援對全表和索引進行repack操作。

  • 對全表進行repack的實現原理如下:

    1. 建立日誌表,記錄repack期間對原表的變更。

    2. 在原表上建立觸發器,將原表的INSERTUPDATEDELETE操作記錄到日誌表中。

    3. 建立原表結構相同的新表並將原表資料匯入其中。

    4. 在新表中建立與原表相同的索引。

    5. 將日誌表裡的變更(即repack期間表上產生的增量資料)應用到新表。

    6. 在系統catalog交換新舊錶。

    7. 刪除舊錶。

    說明
    • pg_repack會在第1、2、6、7步短暫持有原表的排它鎖並阻塞讀寫。其餘步驟pg_repack只需要持有原表的ACCESS SHARE鎖,不阻塞對原表的INSERTUPDATEDELETE操作,但會阻塞DDL操作。

  • 對索引進行repack的實現原理如下:

    1. CREATE INDEX CONCURRENTLY方式建立新索引。

    2. 在系統catalog交換新舊索引(需持有排它鎖,短暫阻塞讀寫)。

    3. DROP INDEX CONCURRENTLY的方式刪除舊索引。

    說明

    pg_repack效果等同於REINDEX CONCURRENTLY,但是比REINDEX CONCURRENTLY更為複雜,如果使用REINDEX CONCURRENTLY,只需要一步就能完成。pg_repack支援該能力的原因是老版本的PostgreSQL不支援REINDEX CONCURRENTLY,從而只能藉助pg_repack來實現。

相關參考

pg_repack的更多資訊可參考pg_repack官方協助文檔