當PolarDB PostgreSQL版(相容Oracle)中的資料表體積日益龐大時,手動管理分區表會變得複雜且耗時。pg_partman是一款PostgreSQL擴充,它通過自動化分區管理解決了這一痛點。該擴充能夠基於時間或序列ID自動建立和維護表分區,並能執行資料保留原則,從而有效簡化了分區表的生命週期管理,提升了資料庫的可維護性和查詢效能。
適用範圍
支援的PolarDB PostgreSQL版(相容Oracle)的版本: Oracle文法相容 2.0,且核心小版本需為2.0.14.19.40.0及以上。
功能簡介
pg_partman擴充的核心是自動化管理基於時間或數字/ID的分區表。它完全基於PostgreSQL內建的聲明式資料分割函數(自pg_partman5.0.1版起),不再使用舊版的觸發器方式。
其工作機制主要包括:
自動建立分區:通過後台維護任務,根據預設的間隔(如每日、每月或每100萬個ID)提前建立未來的分區表,確保新資料能夠無縫寫入。
資料保留原則:自動分離(DETACH)或刪除(DROP)到期的資料分區,有效管理資料生命週期和儲存成本。
預設分區:為每個分區集建立一個預設分區,用於捕獲任何不屬於現有子分區的資料,防止資料丟失。您可以使用配套函數將這些資料移轉到正確的分區。
子分區支援:支援多級分區,例如將年分區再細分為日分區,以滿足複雜的資料群組織需求。
快速上手
本節將通過一個為日誌表按天分區的完整樣本,帶您快速掌握pg_partman的基本用法。建立一個名為log_table的日誌表,按created_at欄位每天建立一個分區,並自動刪除超過7天的資料。
步驟一:安裝外掛程式並建立父表
首先,在您的資料庫中安裝pg_partman外掛程式,然後建立一個用於分區的父表。
-- 1. 在當前資料庫中啟用 pg_partman 擴充
CREATE EXTENSION pg_partman;
-- 2. 建立一個父表,用於儲存日誌資料
-- PARTITION BY RANGE (created_at) 指定了該表將作為分區表,並使用 created_at 列進行定界分割
CREATE TABLE public.log_table (
id bigint GENERATED BY DEFAULT AS IDENTITY,
created_at timestamptz NOT NULL,
message text
) PARTITION BY RANGE (created_at);步驟二:初始化分區集
調用create_parent()函數,將log_table註冊到pg_partman的管理體系中,並定義分區規則。
-- 調用 create_parent 函數初始化分區
-- public.log_table: 要管理的父表
-- created_at: 分區鍵列
-- '1 day': 分區間隔,表示每天建立一個新分區
SELECT create_parent(
p_parent_table := 'public.log_table',
p_control := 'created_at',
p_interval := '1 day'
);執行成功後,pg_partman會自動建立當前及未來幾天的分區。您可以通過\d+ public.log_table命令查看已建立的分區。
步驟三:插入測試資料
向父表log_table中插入一些資料,資料會根據created_at的值自動路由到對應的分區中。
INSERT INTO public.log_table (created_at, message)
SELECT generate_series(
now() - interval '4 days',
now(),
interval '1 hour'
),
'This is a log message.';步驟四:配置保留原則並驗證清理
設定資料保留原則,讓pg_partman自動清理到期資料。將配置log_table只保留最近2天的資料,並自動刪除(DROP)到期的分區。
-- 1. 更新 part_config 表,為 log_table 設定保留原則
UPDATE part_config
SET
retention = '2 days', -- 保留周期為2天
retention_keep_table = false -- 不保留表結構,直接 DROP 到期的分區
WHERE parent_table = 'public.log_table';
-- 2. 手動執行維護任務,觸發保留原則
CALL run_maintenance_proc();
-- 3. 驗證:再次檢查分區列表,確認2天前的分區已被刪除
SELECT partition_schemaname, partition_tablename FROM show_partitions('public.log_table', 'DESC');至此,您已成功配置了一個按天分區並自動清理的日誌表。
注意事項
在使用pg_partman前,請務必瞭解以下限制和風險,以避免資料丟失或服務中斷。
屬性繼承:
pg_partman使用一個模板表來管理部分無法從父表直接繼承的屬性(如特定索引、UNLOGGED狀態等)。對模板表的更改僅對新建立的分區生效,已存在的分區需要手動更新。時區:在進行基於時間的分區時,務必確保資料庫系統、用戶端以及所有調用維護任務的環境使用一致的時區。建議統一使用UTC,以避免因夏令時(DST)等問題導致分區建立失敗或跳過。
子分區:
子分區的主要功能集中於資料的組織及生命週期管理,其對效能提升的作用有限。如果您追求效能最佳化,建議優先調整分區間隔,而非依賴於子分區。過多的子分區會增加管理開銷,並可能耗盡
max_locks_per_transaction資源。子分區不支援邏輯複製(
PUBLICATION/SUBSCRIPTION)。 如果您計劃對分區表使用邏輯複製,請避免使用子資料分割函數。子分區建立 (
create_sub_parent) 是破壞性操作。它會刪除並重建現有的分區以添加下一級分區。在執行前,建議備份相關資料。
對象名稱長度:PostgreSQL對象名有63位元組的限制。
pg_partman會自動截斷表名以適應尾碼,但如果父表名稱過長且相似,可能導致不同分區集下的分區名稱衝突。建議保持父表名簡潔。唯一約束:無法在分區鍵之外的列上建立全域唯一約束或主鍵,這是PostgreSQL聲明式分區的原生限制。
pg_partman允許在每個分區上建立局部唯一約束,但這無法保證整個分區集的全域唯一性。預設分區:請謹慎處理落入預設分區的資料。
pg_partman會建立一個預設分區來接收不屬於任何現有分區的資料。預設情況下,分區維護不會檢查預設分區中的資料來建立新分區。如果資料持續寫入預設分區,應儘快使用partition_data_*系列函數將其遷移至正確分區,並排查資料寫入異常的原因。撤銷分區:執行
undo_partition()期間會暫停所有分區維護。 在撤銷分區操作完成前,run_maintenance()將不會為該分區集建立新分區或執行保留原則。鎖與資源:管理大量分區可能導致鎖資源消耗增加。 如果單個分區集包含數百上千個分區,
run_maintenance()或其他維護操作可能需要調整max_locks_per_transaction參數以避免耗盡記憶體。對於這種情況,建議使用run_maintenance_proc()過程,它會在每個分區集維護後提交事務,減少長事務帶來的鎖佔用。
最佳實務
情境一:按天分區的日誌表(含自動清理)
此情境適用於日誌、審計記錄、物聯網(IoT)時序資料等增長迅速且有明確生命週期的資料。
業務情境
按天對audit_logs表進行分區,資料保留30天,到期資料自動歸檔到另一個模式,而不是直接刪除。
操作步驟
建立父表和初始化分區集:
-- 建立父表 CREATE TABLE public.audit_logs ( log_id uuid NOT NULL, event_time timestamptz NOT NULL, user_id text, details jsonb, PRIMARY KEY (event_time, log_id) ) PARTITION BY RANGE (event_time); -- 初始化分區集,按天分區 SELECT create_parent( p_parent_table := 'public.audit_logs', p_control := 'event_time', p_interval := '1 day' );配置保留與歸檔策略:將超過30天的舊分區表移動到
archive模式下,以便後續進行離線分析或備份。-- 建立用于歸檔的模式 CREATE SCHEMA IF NOT EXISTS archive; -- 更新配置,設定保留原則 UPDATE part_config SET retention = '30 days', -- 保留30天 retention_schema = 'archive' -- 到期後移動到 archive 模式 WHERE parent_table = 'public.audit_logs';當
run_maintenance()運行時,任何完全早於30天前的分區表(例如audit_logs_p2023_10_01)將被從主要磁碟分割集中分離,並將其模式從public更改為archive,變為archive.audit_logs_p2023_10_01。
情境二:按ID分區的業務表
此情境適用於使用者表、商品表等以數字ID為主鍵,並希望通過分區將冷熱資料分離的業務。
業務情境
對orders表按order_id進行分區,每個分區包含1000萬個ID。
決策建議
p_interval的選擇至關重要。應根據業務ID的增長速率和單個分區的合理大小來估算。如果每天新增100萬訂單,10000000的間隔意味著大約每10天建立一個新分區。
操作步驟
建立父表和初始化分區集:
-- 建立父表 CREATE TABLE public.orders ( order_id bigint NOT NULL, customer_id bigint, order_date timestamptz, amount numeric ) PARTITION BY RANGE (order_id); -- 初始化分區集,按ID定界分割 -- 注意:p_interval 即使是數字,也必須以文本形式提供 SELECT create_parent( p_parent_table := 'public.orders', p_control := 'order_id', p_interval := '10000000' -- 每個分區包含1000萬個ID );配置保留原則(可選):如果舊訂單資料可以被歸檔或刪除,可以配置基於ID的保留原則。
-- 保留最近的5000萬個訂單資料 -- 假設當前最大 order_id 是 100,000,000 -- 該策略會刪除 order_id < 50,000,000 的所有分區 UPDATE part_config SET retention = '50000000', retention_keep_table = false WHERE parent_table = 'public.orders';
情境三:遷移現有大表到分區表
此情境適用於將一個已存在的、資料量巨大的單體表(如TB層級)平滑遷移到pg_partman管理的分區結構。
業務情境
將1 TB大小的sensor_data表遷移為按月分區的分區表,並最小化對線上業務的影響。
核心工具
partition_data_proc()過程。它能以小批量、獨立事務的方式遷移資料,避免了長時間的表鎖和事務積壓。
操作步驟
準備工作:建立父表並初始化分區集:
-- 1. 將原表重新命名,作為資料來源 ALTER TABLE public.sensor_data RENAME TO sensor_data_source; -- 2. 建立一個結構相同的新父表 CREATE TABLE public.sensor_data ( reading_id bigserial, device_id text, ts timestamptz NOT NULL, value double precision ) PARTITION BY RANGE (ts); -- 3. 初始化分區集 SELECT create_parent('public.sensor_data','ts','1 month');執行資料移轉:使用
partition_data_proc將sensor_data_source的資料分批遷移到新的分區表sensor_data中。-- 調用資料移轉過程 -- p_source_table: 指定資料來源表 -- p_interval: 每個批次處理的資料時間範圍,建議小於或等於分區間隔。此處設為'1 day',表示每天的資料在一個事務中處理。 -- p_wait: 每個批次之間的等待時間(秒),用於降低對I/O和CPU的持續壓力。 CALL partition_data_proc( p_parent_table := 'public.sensor_data', p_source_table := 'public.sensor_data_source', p_interval := '1 day', p_wait := 1 );該過程會迴圈執行,直到
sensor_data_source表中的所有資料都被遷移完畢。遷移過程中,pg_partman會按需自動建立所需的分區。收尾工作:遷移完成後,驗證資料一致性,然後可以安全地刪除原資料來源表
sensor_data_source。在遷移期間,應用可以繼續向新的分區父表sensor_data寫入新資料。
核心概念
分區類型與間隔
分區類型
pg_partman基於PostgreSQL的聲明式分區,主要支援以下分區方式:
定界分割(Range Partitioning):適用於連續的資料,如時間戳記或序列ID。這是最常用的分區類型。
列表分區(List Partitioning):僅在基於數位ID分區且間隔為
1時支援。
分區間隔(p_interval)
此參數定義了每個子分區所覆蓋的資料範圍。
基於時間:接受任何有效
interval值,如'1 hour'、'1 day'、'1 week'或'1 month'。說明支援的最小時間間隔為1秒,上限則受限於PostgreSQL所支援的最小和最大時間戳記值。
首次運行
create_parent()建立分區集時,在確定要建立的第一個分區時,小於一天的間隔會向下取整。小於24小時但大於1分鐘的間隔將向下取整到最近的小時。
小於1分鐘的間隔則向下取整到最近的分鐘。
系統會建立足夠多的分區以支援到當前真即時間。這意味著在運行
create_parent()時,可能會建立比預期更多的先前分區,而未來分區可能不會全部建立。首次運行run_maintenance()時會修複缺失的未來分區。這是由於需要支援自訂時間間隔所導致的。對於大於或等於24小時的間隔,設定將會如預期一樣進行。
對於等於或大於100年的間隔,外掛程式將使用世紀或千年的實際起始點來確定分區名稱和約束規則。例如,21世紀和第3個千年是從2001年01月01日開始的(不是2000年),這也意味著沒有0年。
基於數字/ID:接受一個表示範圍大小的整數,但需以文本形式提供,如
'1000000'。
周分區:每周的起始日取決於
create_parent()執行時的p_start_partition參數或當前日期。為保證周一為起始日,建議使用date_trunc()函數顯式指定,例如:p_start_partition := to_char(date_trunc('week', CURRENT_TIMESTAMP), 'YYYY-MM-DD HH24:MI:SS')。epoch時間值:如果分區鍵是儲存Unix epoch的整數列,可以通過設定
p_epoch參數(如'seconds'或'milliseconds')讓pg_partman將其作為時間進行分區管理。
子分區(Sub-partitioning)
子分區允許在已有的分區上建立更細粒度的分區,形成多級分區結構(如按年分區,每年再按月子分區)。其主要用於資料群組織和生命週期管理,例如對一個巨大的年分區進行按月歸檔。對於效能提升,子分區通常效果有限,優先考慮調整頂層分區的間隔。
子分區建立 (create_sub_parent) 是破壞性操作。它會刪除並重建現有的分區以添加下一級分區。在執行前,建議備份相關資料。
資料保留原則(Retention)
pg_partman通過run_maintenance()自動執行資料保留原則,管理舊分區的生命週期。核心配置參數如下:
參數 | 描述 | 樣本 |
| 保留周期。
|
|
|
|
|
| 將分離的舊分區移動到指定的歸檔模式,而不是保留在原模式或刪除。此設定優先於 |
|
| 在分離舊分區時是否保留其上的索引。預設為 |
|
對於子分區集,當父表的一個分區被刪除時,如果該分區本身又是分區表,則刪除操作會級聯(CASCADE)到整個繼承樹中的所有下級分區並全部刪除。此外請注意,由pg_partman管理的分區集必須始終至少保留一個分區,因此保留原則永遠不會刪除一個分區集中最後一個分區。
約束排除(Constraint Exclusion)
約束排除是分區表提升查詢效能的關鍵特性。當查詢的WHERE條件可以明確排除某些分區時,查詢最佳化工具會跳過對這些分區的掃描。
pg_partman提供了在非分區鍵列上添加CHECK約束的功能,以增強約束排除的效果。例如,一個按created_at分區的表,如果經常有WHERE device_id = 'A'的查詢,可以為舊分區(資料不再變化)的device_id列添加約束。
核心配置參數如下:
constraint_cols:一個文本數組,指定要在哪些列上建立CHECK約束。例如'{device_id, user_id}'。optimize_constraint:一個整數,定義對多老的分區應用約束。預設值30表示對30個分區間隔之前的舊分區應用約束。constraint_valid:在表上添加約束可能會與表中已有的資料產生衝突,也可能導致pg_partman的維護操作耗時較長。可以設定這些約束在建立時是否為不生效。雖然這樣可以讓約束的建立幾乎瞬間完成,但在驗證之前無法使用約束排除。因此,預設情況下約束會被建立為有效(valid)。
此功能會限制對已添加約束的舊分區進行資料更新。如果需要修改舊資料,為了使
pg_partman能夠正確管理這些約束,請不要重新命名由它管理的約束,可使用reapply_constraints_proc()臨時移除約束。constraint_valid在子分區(Sub-partitioning)中可能無法正常運行。它能夠在第一層分區上正常執行,但在更深層的子分區表集中是否有效則依賴於所使用的分區間隔組合以及optimize_constraint的設定。例如,當將周分區進一步細分為日分區,並且日分區的optimize_constraint設定為7天時,可能無法達到預期效果。儘管周分區的約束能夠被正確建立,但日分區的子分區可能不會建立相應的約束。
模板表與屬性繼承
由於PostgreSQL聲明式分區對某些對象屬性(如非分區鍵上的主鍵/唯一索引、autovacuum設定等)的繼承支援不完善,pg_partman使用模板表機制來確保新建立的分區能正確繼承這些屬性。下表展示了pg_partman是如何管理特定屬性繼承的。如果某個屬性未在表中列出,則表示它通過父表進行管理。
特性 | 從父表繼承 | 從模板繼承 |
非分區列的主鍵 | - | 及以上版本 |
非分區列的唯一索引 | - | 及以上版本 |
非分區列的唯一索引資料表空間 | - | 及以上版本 |
關係特定選項(autovacuum等) | - | 及以上版本 |
未記錄表狀態(UNLOGGED)* | - | 及以上版本 |
非唯一索引 | 及以上版本 | - |
許可權/所有權 | 及以上版本 | - |
屬性:當您調用
create_parent()時,pg_partman會自動建立一個名為parent_table_template的表。您對此模板表所做的任何ALTER TABLE修改(如添加索引、更改autovacuum參數)都會在未來建立新分區時被應用。說明對模板表的修改不會追溯應用於已存在的分區。如需修改,需要手動對舊分區執行
ALTER操作。許可權和所有權:預設情況下,許可權和所有權不會被繼承。如果通過
pg_partman啟用了該功能,請注意這種繼承僅發生在分區建立時,更改後不會自動應用(可通過reapply_privileges()重新應用)。除非你需要直接存取分區,否則通常不需要啟用此功能。如果你需要,可以設定inherit_privileges選項。說明如果您使用
IDENTITY特性來管理序列,則只有在通過父表插入資料時,該特性才支援自動產生新的序列值;而直接向分區插入資料時,該特性不予支援。
模板表特性只是一個臨時解決方案,旨在加快聲明式分區的採用。隨著PostgreSQL核心功能的完善,
pg_partman將逐步淘汰模板表的使用。如果將來某個功能在PostgreSQL核心中得到支援,那麼它將不再通過模板表管理,請提前規劃好升級到主要版本時的相關調整。如果希望使用帶有
USING INDEX子句的REPLICA IDENTITY屬性來支援邏輯複製,請注意該功能僅在實際的父表上建立了所需索引的情況下得以支援,而非在模板表上。由於無法控制REPLICA IDENTITY在父表和模板表上的設定,因此無法判斷哪一個才是正確的標識。為保持與其他標識繼承方法(FULL和NONE)的統一,建議僅選擇父表作為源。由於PostgreSQL在啟用或禁用分區集的父表上的
UNLOGGED屬性時存在處理不一致的問題,pg_partman使用模板表來管理UNLOGGED狀態。當執行ALTER命令時,父表上的該屬性實際上不會發生變化,因此新分區將繼續使用更改前的屬性。這意味著如果你希望將一個分區集從UNLOGGED更改為LOGGED,並讓所有未來分區都繼承這一更改,這是無法實現的。現在通過模板表來管理該屬性後,更改模板表上的屬性將使新建立的分區繼承這一更改。但已存在的分區仍需手動更改,但這一直是如此。更多資訊,請參見Unable to alter partitioned table to set logged。
營運與管理
自動維護
pg_partman的核心維護任務(建立新分區和執行保留原則)由run_maintenance()函數或run_maintenance_proc()過程執行。在PolarDB PostgreSQL版(相容Oracle)中,推薦使用內建的後台背景工作處理序(Background Worker)來自動化此過程,它會根據您設定的間隔自動調用run_maintenance_proc()。
後台背景工作處理序(Background Worker)預設關閉,由於安全原因,暫時不支援您進行配置。如有需要,請前往配額中心,在配額ID為polardb_pg_pg_cron的操作列,單擊申請進行配置。
手動維護
在某些情況下,您可能需要手動觸發維護,例如在調試或需要對特定表進行精細控制時。
CALL run_maintenance_proc();推薦使用此過程。它會為part_config中所有automatic_maintenance為on的分區集執行維護,並在每個分區集維護完成後自動認可事務,減少鎖爭用。SELECT run_maintenance('public.my_table');如果只想對單個分區集執行維護,可以調用此函數並傳入父表名。
監控與警示
在生產環境中,需監控分區維護是否正常運行,以防因分區未及時建立而導致資料寫入失敗。part_config表中的maintenance_last_run欄位記錄了每個分區集最後一次成功運行維護的時間戳記。這是一個關鍵的監控指標。
-- 查詢所有自動維護的分區集中,超過2倍維護間隔仍未成功啟動並執行
SELECT parent_table
FROM part_config
WHERE
automatic_maintenance = 'on'
AND maintenance_last_run < (now() - (SELECT setting::interval * 2 FROM pg_settings WHERE name = 'pg_partman_bgw.interval'));如果此查詢返回任何行,意味著對應的分區集維護可能已中止,需要立即介入排查。
參考函數
pg_partman通過一系列函數提供其核心能力。這些函數根據其用途分為建立、遷移、維護和銷毀四大類。
建立分區
此類函數用於初始化分區集和定義子分區。
create_parent()
此函數用於初始化一個分區集。它基於一個已存在並聲明為分區的父表,配置其分區策略、預建立規則和維護方式。在運行期間,會對父表施加ACCESS EXCLUSIVE鎖。
傳遞給此函數的所有選項都必須與該定義匹配。請將所有預設值、索引、約束、許可權和所有權應用於父表,以便它們傳播到子表。有關處理唯一索引和其他表屬性的說明,請參見模板表與屬性繼承。
預設情況下會建立一個預設分區和一個模板表,除非另有配置。
文法
create_parent(
p_parent_table text
, p_control text
, p_interval text
, p_type text DEFAULT 'range'
, p_epoch text DEFAULT 'none'
, p_premake int DEFAULT 4
, p_start_partition text DEFAULT NULL
, p_default_table boolean DEFAULT true
, p_automatic_maintenance text DEFAULT 'on'
, p_constraint_cols text[] DEFAULT NULL
, p_template_table text DEFAULT NULL
, p_jobmon boolean DEFAULT true
, p_date_trunc_interval text DEFAULT NULL
, p_control_not_null boolean DEFAULT true
, p_time_encoder text DEFAULT NULL
, p_time_decoder text DEFAULT NULL
)
RETURNS boolean參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區集的父表。必須是已存在的、聲明為分區的表,且必須包含模式名。 |
|
| 是 | 無 | 用作分區的控制列,如 說明 當控制列為 |
|
| 是 | 無 | 分區的間隔,參數值應作為文本傳入。取值範圍如下:
|
|
| 否 |
| 分區類型。取值範圍如下:
|
|
| 否 |
| 當分區鍵列是表示時間的整數(epoch)時使用。取值範圍如下:
說明 所有表名將基於時間。除了在控制列上建立一個普通索引外,還請確保在控制列上建立一個基於時間的函數索引(如 |
|
| 否 |
| 提前建立的分區數量。例如,對於日分區, 說明 某些間隔可能會因為閏年、不同月份長度等原因偶爾導致多建立一個分區或遺漏一個分區。這通常不會造成問題,並應能自動糾正(請參見分區類型與間隔)。如果分區落後於 |
|
| 否 |
| 允許手動指定第一個分區的起始值(時間戳記或整數),而不是由系統自動確定。需為一個有效時間戳記(用於基於時間的分區)或正整數(用於基於數字/ID的分區)值。 說明
|
|
| 否 |
| 是否為分區集建立預設分區,用於接收不屬於任何子分區的資料。 |
|
| 否 |
| 是否由全域
|
|
| 否 |
| 為舊分區添加額外 |
|
| 否 |
| 指定一個模板表。新建立的分區將從此模板繼承屬性(如索引、約束等)。若不指定,將自動建立。 |
|
| 否 |
| 用於對齊非標準時間間隔的分區邊界。有效值為PostgreSQL內建 預設情況下, 例如,如果設定了一個9周的間隔,預設情況下 |
|
| 否 |
| 是否要求分區控制列為
|
|
| 否 |
| 當分區鍵為 |
|
| 否 |
| 當分區鍵為 |
create_sub_parent()
此函數用於為一個已存在的分區集建立子分區。這是一個破壞性操作,因為它需要刪除並重建現有的分區,使其轉變為新的父表。
如果計劃依賴表名進行組織,建議為子分區集使用較短的表名。附加在表名末尾的尾碼始終保證存在,無論該分區集使用的是哪種分區類型。較長的表名可能導致原始父表名被截斷,並可能截斷頂層分區尾碼。這是無法控制的,並確保最低層級的分區尾碼保留。
對於第一級子分區,您最初傳遞給
create_parent()的p_parent_table參數值應與傳遞給create_sub_parent()的值完全一致。如果需要進一步進行子分區,則應開始向create_sub_parent()傳遞不同的值(即頂級分區集的子表)。
文法
create_sub_parent(
p_top_parent text
, p_control text
, p_interval text
, p_type text DEFAULT 'range'
, p_default_table boolean DEFAULT true
, p_declarative_check text DEFAULT NULL
, p_constraint_cols text[] DEFAULT NULL
, p_premake int DEFAULT 4
, p_start_partition text DEFAULT NULL
, p_epoch text DEFAULT 'none'
, p_jobmon boolean DEFAULT true
, p_date_trunc_interval text DEFAULT NULL
, p_control_not_null boolean DEFAULT true
, p_time_encoder text DEFAULT NULL
, p_time_decoder text DEFAULT NULL
)
RETURNS boolean
參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 頂級父表的名稱。此函數會將該父表下的所有分區轉變為新的子分區父表。 |
|
| 是 |
| 安全確認標誌。必須設定為 |
其餘參數(p_control或p_interval等)與create_parent()作用相同,但定義的是子分區的策略。例如,如果您有一個按年分區的現有分區集,然後希望將每個年分區按天進行分區,可以使用此函數。
create_partition_time()/create_partition_id()
手動為基於時間或數字/ID的分區集建立特定的子分區。通常由run_maintenance()自動調用,但也可用於在維護周期外按需建立。
文法
create_partition_time(
p_parent_table text
, p_partition_times timestamptz[]
, p_start_partition text DEFAULT NULL
)
RETURNS boolean
create_partition_id(
p_parent_table text
, p_partition_ids bigint[]
, p_start_partition text DEFAULT NULL
)
RETURNS boolean參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 要為其建立子分區的父表。 |
|
| 是 | 無 |
如果分區不存在,它將被建立。如果存在,則使用現有分區並且函數仍將正常退出。請注意,給定的值將用作分區的下界,並影響分區的名稱。因此,請確保給定的時間戳記值與其他分區一致,否則可能會遇到值覆蓋的間隙。 |
|
| 是 | 無 |
如果分區不存在,它將被建立。如果存在,則使用現有分區並且函數仍將正常退出。請注意,給定的值將用作分區的下界,並影響分區的名稱。因此,請確保給定的整數值與其他分區一致,否則可能會遇到值覆蓋的間隙。 |
|
| 否 |
| 用於子分區情境,指定子分區的起始值。 |
遷移資料
此類函數用於將存量資料或誤入預設分區的資料移轉到正確的分區中。
partition_data_time()/partition_data_id()
將父表、預設分區或指定源表中的資料移轉到對應的分區中。如果目標資料分割不存在,函數會自動建立。它還可以修複插入到預設表中的資料。
如果您需要自動分區大量資料,建議使用
partition_data_proc過程以較小的批次提交資料。這將有效減少由長時間啟動並執行事務和資料佔用引起的問題。對於子分區集,必須從最高層次開始逐層進行資料分區。這意味著您必須首先運行此函數,然後執行
create_sub_parent()以建立額外的分區層級。隨後,在每個新建立的子父表上再次運行此函數。
文法
partition_data_time(
p_parent_table text
, p_batch_count int DEFAULT 1
, p_batch_interval interval DEFAULT NULL
, p_lock_wait numeric DEFAULT 0
, p_order text DEFAULT 'ASC'
, p_analyze boolean DEFAULT true
, p_source_table text DEFAULT NULL
, p_ignored_columns text[] DEFAULT NULL
)
RETURNS bigint
partition_data_id(
p_parent_table text
, p_batch_count int DEFAULT 1
, p_batch_interval bigint DEFAULT NULL
, p_lock_wait numeric DEFAULT 0
, p_order text DEFAULT 'ASC'
, p_analyze boolean DEFAULT true
, p_source_table text DEFAULT NULL
, p_ignored_columns text[] DEFAULT NULL
)
RETURNS bigint
參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區集的父表(需包含模式名)。 |
|
| 否 |
| 一次函數調用中處理的批次數。 |
|
| 否 |
| 每個批次遷移的資料區間大小。若不指定,則使用分區表的自身間隔。 重要 如果從預設表中移動資料,則此值不得小於分區間隔。如果從非分區集的預設表源中移動資料,則可以將此間隔設定得比分區間隔小,以協助避免在長時間啟動並執行事務中移動大量資料。 |
|
| 否 |
| 等待行鎖的秒數。 |
|
| 否 |
| 資料移轉的順序。
|
|
| 否 |
| 是否在建立新分區後對父表執行 |
|
| 否 |
| 指定一個源表,將其資料移動到分區集中。若不指定,則從預設分區遷移。 |
|
| 否 |
| 遷移資料時要忽略的列名數組。主要用於處理含 |
partition_data_proc()
此函數是一個預存程序,它以獨立的事務批次迴圈調用partition_data_*函數。建議在遷移大量資料時使用此過程,以避免長事務和鎖佔用。
文法
partition_data_proc (
p_parent_table text
, p_loop_count int DEFAULT NULL
, p_interval text DEFAULT NULL
, p_lock_wait int DEFAULT 0
, p_lock_wait_tries int DEFAULT 10
, p_wait int DEFAULT 1
, p_order text DEFAULT 'ASC'
, p_source_table text DEFAULT NULL
, p_ignored_columns text[] DEFAULT NULL
, p_quiet boolean DEFAULT false
)參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區集的父表。 |
|
| 否 |
| 迴圈執行的次數。若不設定,將處理源表中的所有資料。 |
|
| 否 |
| 作為 |
|
| 否 |
| 等待行鎖的秒數。 |
|
| 否 |
| 嘗試擷取鎖的次數。 |
|
| 否 |
| 每個批次提交後暫停秒數,以降低寫入負載。 |
|
| 否 |
| 資料移轉的順序。
|
|
| 否 |
| 資料來源表。 |
|
| 否 |
| 遷移資料時要忽略的列。 |
|
| 否 |
| 過程不能傳回值,因此預設會發出 |
維護分區
此類函數用於日常的分區管理、監控和資訊查詢。
run_maintenance()
pg_partman的核心維護函數,應通過cron或後台背景工作處理序(Background Worker)定期調用。它負責自動建立新分區和執行資料保留原則。
文法
run_maintenance(
p_parent_table text DEFAULT NULL
, p_analyze boolean DEFAULT false
)
RETURNS void參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 否 |
| 維護的分區集。
|
|
| 否 |
| 是否在建立新分區後對父表運行 對於大型分區集而言, |
run_maintenance_proc()
run_maintenance() 的過程版本。它為每個分區集的維護使用獨立的事務,可以減少在管理大量分區集時間長度事務導致的鎖佔用。Background Worker未使用此過程,使用標準的run_maintenance()函數。
文法
run_maintenance_proc(
p_wait int DEFAULT 0
, p_analyze boolean DEFAULT NULL
)參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 否 |
| 在維護每個分區集之間等待的秒數。 |
|
| 否 |
| 同 |
check_default()
檢查所有由pg_partman管理的預設分區中是否存在資料,並返回包含資料的預設表及其行數。這是監控分區是否正常工作的重要手段。可以使用partition_data_time()和partition_data_id()將資料從這些父表/預設表移動到正確的分區中。
文法
check_default(
p_exact_count boolean DEFAULT true
)參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 否 |
| 是否返回精確的行數。設為 |
show_partitions()
列出給定分區集的所有分區。
表按照分區間隔的邏輯順序返回,而不是按照其名稱的本地排序次序。
文法
show_partitions(
p_parent_table text
, p_order text DEFAULT 'ASC'
, p_include_default boolean DEFAULT false
)
RETURNS TABLE (
partition_schemaname text
, partition_tablename text
)參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區集的父表。 |
|
| 否 |
| 結果的排序方式。
|
|
| 否 |
| 是否在結果中包含預設分區。 |
show_partition_name()
根據給定的值,返回其應該歸屬的子分區名稱,無論該分區是否實際存在。
文法
show_partition_name(
p_parent_table text
, p_value text
, OUT partition_schema text
, OUT partition_table text
, OUT suffix_timestamp timestamptz
, OUT suffix_id bigint
, OUT table_exists boolean
)
RETURNS record參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區集的父表。 |
|
| 是 | 無 | 一個時間或數字/ID值(以文本形式傳入),用於確定其所屬的分區。 說明 如果使用epoch時間分區,請給出時間戳記值,而不是整數epoch值(可以使用 |
|
| - | - | 分區模式名稱。 |
|
| - | - | 分區名稱。 |
|
| - | - | 分區名尾碼。 |
|
| - | - | 該分區是否實際存在。 |
show_partition_info()
根據分區名,返回該分區的邊界值資訊。
文法
show_partition_info(
p_child_table text
, p_partition_interval text DEFAULT NULL
, p_parent_table text DEFAULT NULL
, OUT child_start_time timestamptz
, OUT child_end_time timestamptz
, OUT child_start_id bigint
, OUT child_end_id bigint
, OUT suffix text
)
RETURNS record參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區的名稱(需包含模式名)。 |
|
| 否 |
| 指定分區間隔以計算邊界。若不提供,則從 |
|
| 否 |
| 提供父表名以最佳化內部查詢。 |
|
| - | - | 如果分區集是基於時間的,則函數返回這些輸出參數的值。否則返回NULL。 說明 起始值( |
|
| - | - | 如果分區集是基於整數的,則函數返回這些輸出參數的值。否則返回NULL。 說明 起始值( |
|
| - | - | 輸出附加到分區名中標識其內容的文本部分(不包括 |
apply_constraints()/drop_constraints()/reapply_constraints_proc()
管理在part_config的constraint_cols列中定義的額外CHECK約束。
apply_constraints():對給定分區集的分區應用約束,約束名均以partmanconstr_為首碼。說明不需要手動調用此函數來維護自訂約束。建立新分區時會自動管理向舊分區添加約束
如果
pg_partman約束已經存在於分區上,函數會跳過已存在的約束,避免重複建立。如果給定的列全部為NULL值,則不會建立約束。
如果提供了分區參數,則僅對該分區應用約束。
如果未提供分區參數,則約束將應用於最後一個比
optimize_constraint值更早的分區。例如,如果optimize_constraint值為30,則會對當前分區往前第31個分區應用約束(前提是分區預建立已保持最新)。如果需要對所有舊分區應用約束,請使用
reapply_constraints_proc過程。此方法具有選項,可以在儘可能減少效能影響的前提下簡化約束應用。p_job_id用於內部用途,允許將日誌合并到調用此函數的原始作業中。
apply_constraints( p_parent_table text , p_child_table text DEFAULT NULL , p_analyze boolean DEFAULT FALSE , p_job_id bigint DEFAULT NULL ) RETURNS voiddrop_constraints():刪除由pg_partman為在part_config中配置的列建立的約束。這使得在需要編輯舊資料且約束不允許時,可以輕鬆清理約束。說明僅刪除以
partmanconstr_*開頭的給定分區和配置列上的約束。如果需要刪除所有分區上的約束,請使用
reapply_constraints_proc過程。此方法具有選項,可以在儘可能減少效能影響的前提下簡化約束刪除。p_debug參數將顯示使用的約束刪除語句。
drop_constraints( p_parent_table text , p_child_table text , p_debug boolean DEFAULT false ) RETURNS voidreapply_constraints_proc():在所有分區上批量應用或刪除約束,分批提交以避免鎖佔用。reapply_constraints_proc( p_parent_table text , p_drop_constraints boolean DEFAULT false , p_apply_constraints boolean DEFAULT false , p_wait int DEFAULT 0 , p_dryrun boolean DEFAULT false )
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 已建立的分區集的父表。 |
|
| 否 |
| 刪除所有由 |
|
| 否 |
| 對所有比 |
|
| 否 |
| 在對一張表應用完約束刪除或添加後等待的秒數,然後再繼續下一張表。 |
|
| 否 |
| 運行此過程時不實際執行刪除/應用約束命令。僅輸出將對哪些表執行命令作為 |
其他維護函數
dump_partitioned_table_definition():產生用於重建分區集配置的create_parent()以一個用於設定part_config中儲存的額外參數的UPDATE語句。說明目前僅支援單級分區集。
p_ignore_template用於產生的SQL在運行前需要先建立模板表。如果你未對模板表進行任何修改,則在此處傳入true是安全的,產生的SQL將告訴pg_partman產生新的模板表。但為了安全起見,建議使用pg_dump匯出模板表並在使用產生的SQL之前恢複它們,以保持任何模板覆蓋設定。
dump_partitioned_table_definition( p_parent_table text, p_ignore_template_table boolean DEFAULT false ) RETURNS textpartition_gap_fill():檢查並填充分區序列中可能存在的空缺分區。從當前最小的分區開始,根據分區間隔填充遇到的任何空缺,直到當前最大的分區。返回建立的分區數量。如果沒有建立任何分區,則返回0。partition_gap_fill( p_parent_table text ) RETURNS integerreapply_privileges():將父表的所有權和許可權重新應用到所有分區。說明父表擁有的許可權將被授予所有分區,父表未擁有的許可權將被撤銷(
CASCADE)。被檢查的許可權包括:
SELECT、INSERT、UPDATE、DELETE、TRUNCATE、REFERENCES和TRIGGER。對於大型分區集而言,這可能是一個非常耗時的操作,因此該操作被設計為一個獨立啟動並執行函數。該函數僅對與父表不同的許可權進行應用,但仍需對每個子分區及其所有單獨許可權進行系統目錄的尋找和比較。
reapply_privileges( p_parent_table text ) RETURNS voidstop_sub_partition():停止對某個子分區集的自動維護,同時保留其父級分區的維護。預設情況下,如果您撤銷一個分區,該分區同時也是分區,除非同時撤銷其父分割集,否則不會阻止該父分割集的其他分區繼續進行子分區。為瞭解決這種情況,即您可能不希望刪除父表但又不想繼續建立子分區,您可以使用此函數。說明此函數僅從
part_config_sub表中刪除父表條目。stop_sub_partition( p_parent_table text ) RETURNS boolean
銷毀分區
此類函數用於撤銷分區結構或根據保留原則刪除舊分區。
undo_partition()
將一個分區集的資料從所有分區移動到單個目標表中,並解除分區結構。這是一個資料移動操作,請謹慎使用。
當運行該函數時,配置表中的
undo_in_progress列會被設定為true。這將導致所有分區的建立和保留管理停止。預設情況下,分區不會被刪除(
DROP),而是被分離(DETACH)。這將使原來的分區成為空白的獨立表。如果沒有手動設定任何批量參數,每次運行函數時將從一個分區中移動全部資料到目標表。
一旦所有分區都被取消繼承/刪除,配置資料將自動從
pg_partman中移除。對於子分區表,您需要從最低層級的父表開始進行反分區操作,然後再向上逐層進行。
文法
undo_partition(
p_parent_table text
, p_target_table text
, p_loop_count int DEFAULT 1
, p_batch_interval text DEFAULT NULL
, p_keep_table boolean DEFAULT true
, p_lock_wait numeric DEFAULT 0
, p_ignored_columns text[] DEFAULT NULL
, p_drop_cascade boolean DEFAULT false
, OUT partitions_undone int
, OUT rows_undone bigint)
RETURNS record
參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區集的父表。需帶有模式名,並且需與 |
|
| 是 | 無 | 一個帶有模式名的表,用於接收舊分區表的資料。 |
| int | 否 |
| 單次調用中處理的批次數。 |
|
| 否 |
| 每個批次移動的資料區間大小。可以設定得比分區間隔更小,從而將非常大的分區拆分為更小的提交批次。如果沒有指定或提供的間隔大於分區間隔,則使用配置的分區間隔。注意該參數的值必須以文本形式傳入。 |
|
| 否 |
| 資料移轉後是保留還是刪除空的分區。
說明 至少需要兩個批次才能真正從分區集中刪除一個表。 |
|
| 否 |
| 用於設定在逾時前等待表或行解鎖的秒數。為0時,表示無限等待。 |
|
| 否 |
| 此選項允許在將資料從分區移動到目標表時過濾掉特定列。這通常僅在使用 |
|
| 否 |
| 是否串聯刪除子分區。僅在 說明 串聯刪除時,會導致刪除父表時同時刪除其下所有子分區表。 |
undo_partition_proc()
undo_partition()的過程版本。建議在撤銷包含大量資料的分區時使用此過程,以分批提交,避免長事務。
文法
undo_partition_proc(
p_parent_table text
, p_target_table text DEFAULT NULL
, p_loop_count int DEFAULT NULL
, p_interval text DEFAULT NULL
, p_keep_table boolean DEFAULT true
, p_lock_wait int DEFAULT 0
, p_lock_wait_tries int DEFAULT 10
, p_wait int DEFAULT 1
, p_ignored_columns text[] DEFAULT NULL
, p_drop_cascade boolean DEFAULT false
, p_quiet boolean DEFAULT false
)參數說明
其參數與undo_partition()類似,並增加了部分參數用於控制批處理行為。
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 否 |
| 作為 |
|
| 否 |
| 設定過程嘗試等待 |
|
| 否 |
| 在每次提交(批次)之間讓過程暫停指定的秒數,以減少寫入負載。 |
|
| 否 |
| 子過程不能傳回值,因此預設會發出 |
drop_partition_time()/drop_partition_id()
根據保留原則,手動觸發刪除或分離舊錶。預設情況下,舊錶僅被取消繼承,而不會被實際刪除。建議使用配置了保留原則的run_maintenance()函數來自動刪除舊錶,而不是直接調用該函數。
文法
drop_partition_time(
p_parent_table text
, p_retention interval DEFAULT NULL
, p_keep_table boolean DEFAULT NULL
, p_keep_index boolean DEFAULT NULL
, p_retention_schema text DEFAULT NULL
, p_reference_timestamp timestamptz DEFAULT CURRENT_TIMESTAMP
)
RETURNS int
drop_partition_id(
p_parent_table text
, p_retention bigint DEFAULT NULL
, p_keep_table boolean DEFAULT NULL
, p_keep_index boolean DEFAULT NULL
, p_retention_schema text DEFAULT NULL
)
RETURNS int參數說明
參數 | 類型 | 是否必須 | 預設值 | 描述 |
|
| 是 | 無 | 分區集的父表。 |
|
| 否 |
| 手動指定保留原則。若不提供,則使用 |
|
| 否 |
| 是否在取消繼承的同時保留或刪除表。
|
|
| 否 |
| 在取消繼承分區時是否保留或刪除索引。
|
|
| 否 |
| 將到期的表移動到此模式下進行歸檔,而不是刪除。 |
|
| 否 |
| (僅限時間分區)用於指定一個不同的參考時間戳記,以確定哪些分區應被影響。 |
配置表
pg_partman的所有行為都由兩個核心配置表驅動。在通過create_parent()或create_sub_parent()函數建立分區集時,相應的配置會自動插入這些表中。您也可以直接修改這些表中的記錄來動態調整分區集的行為。
part_config
此表是pg_partman的主配置中心,儲存所有頂級父表的分區策略和維護設定。
配置項(列名) | 資料類型 | 預設值 | 描述 |
|
| 無 | 分區集的父表名。 |
|
| 無 | 用作分區依據的控制列名,需為時間或整數類型的列。 |
|
| 無 | 分區的間隔。時間分區為 |
|
|
| 分區類型,目前支援 |
|
|
| 預建立的分區數量。表示在當前分區之外,始終保持存在多少個未來的分區。 |
|
|
| 控制此分區集是否由全域 |
|
| 無 | 用於新分區的模板表。新建立的分區將從此模板繼承索引、約束等無法從父表繼承的屬性。 |
|
|
| 資料保留原則。時間分區為 |
|
|
| 當舊分區到期時,將其移動到此指定的模式下進行歸檔,而不是刪除。此選項優先於 |
|
|
| 控制到期分區的處理方式。
|
|
|
| 控制在分離表的同時是否保留其上的索引。
|
|
|
| 控制是否將被分離的表保留在其原有的邏輯複製發布(Publication)中。
|
|
|
| 當分區鍵列是表示時間的整數(epoch)時使用。
|
|
|
| 一個列名數組。 |
|
|
| 定義了多舊的分區會應用 |
|
|
| 控制
|
|
|
| 是否在沒有新資料寫入的情況下,依然持續建立新的時間分區。
|
|
| 無 | 用於產生分區名稱尾碼的日期時間格式化字串(例如 |
|
|
| 是否將父表的許可權和所有權繼承給所有分區。僅在需要直接存取分區時開啟。
|
|
|
| 維護任務是否忽略預設分區中的資料來決定是否建立新分區。為修複問題可臨時設為 |
|
|
| 定義
|
|
|
| 維護運行時要重新整理的邏輯複製訂閱的名稱。如果分區集訂閱了一個會添加/刪除表的發布,並且你需要分區集感知這些更改,則必須使用此選項指定該訂閱名稱。否則,除非通過其他方式重新整理訂閱,否則訂閱將永遠不會感知發行者新增的表。更多資訊,請參見ALTER SUBSCRIPTION。 |
|
|
| 標記子分區集是否已建立完畢。當存在大量子分區集時,允許 |
|
|
| 當 |
|
|
| 記錄此分區集最後一次成功運行維護的時間戳記。可用於監控指標以確保分區維護正常運行。 |
part_config_sub
此表用於儲存子分區的配置。其結構與part_config基本一致,但有一個關鍵區別:它使用sub_parent列來標識其所屬的上一級父表。
sub_parent(text):子分區集的父表名,該表本身是頂級父表的一個分區。其他列:表中所有其他的列(如
partition_interval、retention、premake等)的含義與part_config中完全相同,但其範圍是當前子分區集。
您無需在此重複查看所有列的定義。只需理解,當pg_partman維護一個子分區集時,它會從part_config_sub表中尋找以sub_parent為鍵的配置行,並應用該行中定義的策略。