【问题标题】:Unique constraint that includes serial primary key in postgresql在 postgresql 中包含串行主键的唯一约束
【发布时间】:2026-02-06 09:15:02
【问题描述】:

我有一个布局如下的 postgresql 表:

create table bar(
    bar_id serial primary key,
    ... other columns
)
create table foo(
    foo_id serial primary key,
    bar_id bigint not null,
    ... other columns
)
create table baz(
    baz_id serial primary key,
    foo_id bigint not null references foo(foo_id),
    bar_id bigint not null references bar(bar_id),
    constraint fk_fb foreign key (foo_id, bar_id) references foo(foo_id, bar_id)
)

我想在另一个表 (baz) 中同时引用 foo_id 和 bar_id 并且有一个外键约束,所以我需要给 (foo_id, bar_id) 添加一个唯一约束。 foo_id 是主键这一事实保证了 foo_id 和 bar_id 的组合是唯一的,即使 bar_id 的每个值都相同。我的问题是在 (foo_id, bar_id) 上添加唯一约束是否会影响性能,或者 postgresql 是否足够聪明,知道 foo_id 作为主键在整个表中是唯一的这一事实意味着存在不需要对 bar_id 做任何事情。

表 foo 包含 baz 中不存在的行,因此从 foo 表中删除 bar_id 将不起作用。

【问题讨论】:

  • 我想在另一个表中同时引用 foo_id 和 bar_id:为什么?序列列足以唯一标识foo 表中的一行。
  • @GMB 也许这样ON UPDATE CASCADE 将保持foobaz 同步? (不是说这是个好主意)
  • "从 foo 表中删除 bar_id 是行不通的。" - 但是从 baz 表中删除 bar_id 列怎么样?并让foo.bar_id 引用bar?

标签: postgresql


【解决方案1】:

添加另一个UNIQUE 约束会降低性能,因为这样的约束是通过索引实现的,该索引需要针对表上的每次数据修改进行更新。

如果此表上的 DML 性能非常重要,您可以考虑的一件事是在两列上定义主键。那么您将失去foo_id 的唯一性保证,但您不必为额外的索引付出代价。

也许您还可以提出一种替代数据模型,该模型不需要您使用外键引用两列,就像 GMB 在他的回答中建议的那样。

【讨论】: