pg_partman
1. 概述
pg_partman 用于简化和自动化对 PostgreSQL 原生声明式分区表的管理,它提供了自动创建、维护和清理分区的功能,尤其是基于时间范围和整数范围分区。
PostgreSQL 支持的 3 种分区方式:范围分区、列表分区、哈希分区。其中,pg_partman 扩展不支持哈希分区,对列表分区支持有限,它主要用于按时间(如天、周、月)或数值区间(如自增 ID)进行的范围分区。
注意,pg_partman 作为 PostgreSQL 的扩展,专门设计用于对 PostgreSQL 的分区表进行管理,所以它不支持在 Oracle 兼容模式下运行。
版本:5.2-STABLE
开源协议:PostgreSQL License
2. 安装启用
3. 使用流程
pg_partman 本身不负责创建分区主表,它的主要功能是在已有分区表的基础上,自动创建和维护分区子表。所以在使用 pg_partman 之前,要先手动创建一个已经启动分区机制的主表。主表创建完成后,先将主表注册给 pg_partman 管理,注册时会指定分区策略等。注册成功会在数据库中创建一个命名为 template_[schema]_[table_name] 的模板表,这个模板表不会存数据,是后面所有子分区的模板。注册完成后必须通过手动调用或通过脚本自动调用 run_maintenance()/run_maintenance_proc() 来创建分区、清理分区。
下面给出两个使用案例,有其他使用需求请参考 pg_partman 官方文档。
4. 案例一 基于时间字段分区
场景假设:有一个日志表 logs,每天产生大量数据,希望按天自动创建子分区,并保留最近 30 天的数据,自动删除更旧的分区。
4.1. 手动创建分区主表
CREATE TABLE public.logs (
id BIGSERIAL,
log_time TIMESTAMPTZ NOT NULL DEFAULT now(),
message TEXT
) PARTITION BY RANGE (log_time);
4.2. 注册分区主表到 pg_partman
注册 logs 表,按天分区,从当前时间开始预创建未来 3 天,保留最近 30 天:
SELECT partman.create_parent(
p_parent_table => 'public.logs', -- 要管理的分区父表,注意要显式带 SCHEMA
p_control => 'log_time', -- 分区字段
p_interval => '1 day', -- 按天分区
p_type => 'range', -- 使用范围分区
p_premake => 3, -- 预创建3个未来的分区
p_start_partition => '2025-12-24', -- 起始分区
p_default_table => false -- 是否创建默认分区
);
上面 SQL 会从 2025-12-24 开始按天创建分区,并且预创建以当前服务器时间为基准的未来 3 个分区,分区命名以该分区表的起始时间为后缀。
INSERT INTO public.logs (log_time) VALUES ('2025-12-28 00:01:00');
4.3. 注册清理(可选)
UPDATE partman.part_config SET retention = '30 days' WHERE parent_table = 'public.logs';
4.4. 手动维护
select partman.run_maintenance();
或
CALL partman.run_maintenance_proc();
|
调用 run_maintenance() 时,会根据分区策略自动预生成新的分区表,预生成的基准是表的分区字段的数据。如果最近一条插入数据的 log_time 字段是 20251228,则以此为基准预生成 logs_p20251229/logs_p20251230/logs_p20251231 三张分区子表。 另外,run_maintenance() 也会执行清理机制,清理机制以服务器时间为基准,上面的例子会将服务器当前时间 30 天之前的子表从主表记录上移除,但不会真正删除,以避免误删数据。此时 \d+ logs 查看分区主表的分区信息,看不到 30 天之前被移除的表,但 \dt 查看数据库所有的表,能看到被移除分区的子表依然存在。这些子表可以手动删除。 |
4.5. 自动维护
使用操作系统的 crontab:
创建 shell 脚本 /usr/local/bin/partman_maintenance.sh:
cd /usr/local/bin vi partman_maintenance.sh
脚本内容:
#!/bin/bash psql -U [db_username] -d [db_name] -c "CALL partman.run_maintenance_proc();"
赋予执行权限:
chmod +x partman_maintenance.sh
配置执行计划:
crontab -e # 添加一行,配置每天凌晨一点执行一次 0 1 * * * /usr/local/bin/partman_maintenance.sh
5. 案例二 基于自增ID字段分区
场景假设:创建一个订单表,每 10,000 个 ID 创建一个分区。
5.1. 手动创建分区主表
CREATE TABLE orders (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 分区键
amount NUMERIC
);
5.2. 注册分区主表到 pg_partman
SELECT partman.create_parent(
p_parent_table => 'public.orders', -- 要管理的分区父表,注意要带 SCHEMA
p_control => 'id', -- 分区字段
p_interval => '10000', -- 每1万条数据一个分区
p_type => 'range', -- 使用范围分区
p_premake => 3, -- 预创建3个未来的分区
p_start_partition => '0', -- 起始分区
p_default_table => false -- 是否创建默认分区
);