RDS PostgreSQL pg_partman插件创建分区表失败

问题描述

在使用pg_partman插件对RDS PostgreSQL数据库进行分区表管理时,通过接口create_parent为一张父表创建分区,可能会遇到以下错误:

ERROR: duplicate key value violates unique constraint "part_config_parent_table_pkey"

问题原因

pg_partman使用表part_config来管理表分区的信息。然而,该表仅在使用插件接口时维护相关分区信息。如果之前创建了同名分区表,并且采用DROP TABLE直接删除了该表,则part_config表中的相关信息不会被清理。再次创建同名的分区表时,将会出现错误:ERROR: duplicate key value violates unique constraint "part_config_parent_table_pkey"

复现方法

-- 创建分区表
CREATE TABLE part_test(a INT PRIMARY KEY,b INT) PARTITION BY RANGE (a);
SELECT create_parent(p_parent_table=>'public.part_test',p_control=>'a',p_interval=>'10',p_premake=>10);
DROP TABLE part_test;

-- 创建同名分区表
CREATE TABLE part_test(a INT PRIMARY KEY,b INT) PARTITION BY RANGE (a);
SELECT create_parent(p_parent_table=>'public.part_test',p_control=>'a',p_interval=>'10',p_premake=>10);

解决方案

pg_partman提供了接口undo_partition用于解除父表的分区,在删除表前,需要先执行这个函数,对元数据进行清理。例如,删除part_test表前,可以使用如下SQL,清理元数据。

-- 创建一张相同结构的非分区表
CREATE TABLE part_test_bak(a INT PRIMARY KEY,b INT);
-- 撤消分区,将分区表的数据迁移到非分区表里
SELECT undo_partition('public.part_test',p_target_table := 'public.part_test_bak');
-- 删除原父表
DROP TABLE part_test;

在使用插件的场景下,直接使用DROP TABLE命令删除父表并不是最佳实践。为了确保在删除表时相关的元数据得到及时更新,可以考虑利用事件触发器(EVENT TRIGGER)。通过这一机制,可以在执行DDL操作时,自动处理和更新元数据表,从而维护数据的一致性和完整性。

更多相关讨论,请参见pg_partman社区