PostgreSQL 分区表只用 id 作主键,报 must include all partitioning columns
按日期分区后不能只用id建立父表主键:核对完整分区键,区分复合标识与全表唯一编号,连同外键和应用访问方式选择模型。
表按 placed_on 分区,添加 PRIMARY KEY (id) 时收到:
ERROR: unique constraint on partitioned table must include all partitioning columns
DETAIL: PRIMARY KEY constraint on table "events" lacks column "placed_on" which is part of the partition key.
这不是 id 列少了一个普通索引。分区父表的主键或唯一约束必须包含全部分区键列;每个分区自己的唯一索引只能检查该分区内的数据,不能独立保证另一个分区没有相同的 id。
下面针对 PostgreSQL 18 的声明式分区规则。先看完整 DETAIL 指出的缺失列,再检查实际分区定义;普通非分区表以及其他数据库的全局索引机制不能直接套用。
对照分区键与主键的列集合
在正确数据库中检查目标父表。public.events 是示例名称,需要替换为实际 schema 和表名:
SELECT c.oid::regclass AS table_name,
pg_get_partkeydef(c.oid) AS partition_key
FROM pg_class AS c
WHERE c.oid = to_regclass('public.events')
AND c.relkind = 'p';
没有返回行时,先确认对象是否存在、是否真是分区父表,以及连接的数据库是否正确。返回的分区键若不止一列,主键需要包含全部列;不是任选其中一列就够。
还要检查分区键是否使用表达式或函数。分区表主键或唯一约束的这项规则要求分区键不含它们;不能把表达式中出现的某个原始列补进主键,就认为一定满足条件。
接受复合标识时,把分区键纳入主键
如果业务允许一条记录由日期与编号共同标识,可以把它们组成主键。下面只展示新表定义,假定同名表不存在;不要删除现有业务表来照搬示例:
CREATE TABLE public.events (
id bigint NOT NULL,
placed_on date NOT NULL,
payload jsonb,
PRIMARY KEY (placed_on, id)
) PARTITION BY RANGE (placed_on);
CREATE TABLE public.events_2026_10
PARTITION OF public.events
FOR VALUES FROM ('2026-10-01') TO ('2026-11-01');
主键只保证 (placed_on, id) 这个组合唯一。同一个 id 配上不同日期,仍然可以存在于表中,甚至落在不同分区。只有业务确实接受这个身份规则,才适合采用该定义;不能为使建表通过而悄悄放宽“编号全表唯一”的要求。
应用查找、更新、去重和关联也应使用约定的完整标识。已有子表只保存 id 时,改成复合主键并不会自动补齐关联所需日期,相关外键还要重新设计。可结合复合键的外键引用条件核对,不能机械地在子表随便填一个日期。
编号必须全表唯一时,重新选择模型
如果 id 单独就必须标识整个数据集,简单增加 placed_on 到主键不能满足需求。可以评估普通非分区表,或按 id 本身分区,使唯一键包含真正的分区键。这会改变按日期保留和删除数据的维护方式,也可能改变查询裁剪效果,应先核对访问和维护需求。
各分区分别建立 UNIQUE (id) 只能保证各自分区内唯一。使用序列或 identity 生成编号,也不能替代约束:手工导入、显式编号或序列调整仍可能引入不符合规则的值。
另设非分区的编号登记表可以作为一种完整性设计方向,但只有所有写入入口都遵守登记与数据写入的事务规则时才成立,还涉及更新、删除、回填和外键关系。它不是给现有分区表执行一条 SQL 就能补上的全局唯一索引。
现有数据与应用一起验收
改已有表前保留数据备份、表与分区定义、所有依赖外键和应用查找规则。先检查按预期键分组是否有重复,确认分区键里的空值怎样处理;添加主键会要求相关列非空,并检查已有数据,也可能等待或阻塞业务。
如果已经建立按日期的分区表,不能简单用 ALTER TABLE 把它切换为另一种分区方案或普通表。需要制定数据迁移、应用切换与回退过程。不要使用 CASCADE 清理依赖来绕过检查,也不要为了通过主键校验直接删除无法判断归属的记录。
最终应确认父表主键包含完整分区键,相关子分区索引和外键符合选定模型;同时分别核对相同组合和“相同编号、不同日期”的处理是否符合业务约定。数据库接受了主键定义,只证明约束满足语法与数据条件,不能替业务确认编号含义。


