是自己做唯一约束还是作为主键?

Unique constraints on their own or as a primary key?

使用这样的 table 模式有什么好处吗:

CREATE TABLE review (
    review_id SERIAL PRIMARY KEY,
    account_id INT REFERENCES account(account_id) NOT NULL, 
    product_id INT REFERENCES product(product_id) NOT NULL, 
    rating SMALLINT NOT NULL, 
    comment TEXT,
    UNIQUE (account_id, product_id)
);

或者约束本身应该是主键,像这样:

CREATE TABLE review (
    CONSTRAINT review_pkey (account_id, product_id) PRIMARY KEY,
    account_id INT REFERENCES account(account_id) NOT NULL, 
    product_id INT REFERENCES product(product_id) NOT NULL, 
    rating SMALLINT NOT NULL, 
    comment TEXT,
);

第二个版本显然更可取,因为它需要少一个列和一个索引,而且没有缺点。

列很明显,索引不明显,因为您忘记添加它们: 您需要在所有外键列上建立索引,以便可以快速删除引用的 table。使用人工主键,您需要 review_idaccount_idproduct_id 上的索引,如果没有,您可以使用 (account_id, product_id)product_id 上的索引。

唯一会提倡第一种解决方案的人是持有宗教信仰的人,即每个 table 无论如何都必须有一个人工生成的数字主键。实际上,从引用的 tables 中人工生成的两个键的组合同样好。

除了宗教、习惯、个人偏好和某些客户端工具的便利性之外,还有其他充分的理由需要额外的代理 PK,如您的第一个示例所示。

如果您要使用来自其他 table 的外键引用 table:

  • 引用table(s)只需要包含单个代理PK列作为FK引用,更小、更快、更简单。如果引用 table(s) 有很多行而 review 没有,则单个实例可能已经超过 review 的额外成本。否则,多个实例可能。
    对于在 许多 行中引用的小型查找 table,甚至可以考虑 smallserial 代理 PK - 如果 实际上 帮助。参见:

    • Calculating and saving space in PostgreSQL
  • 通常,在引用 table 的 FK 列上也会有一个索引。您使用两个 integer 的示例最有利于多列 PK / FK,因为它将索引大小保持在最低限度。两个 integer 列上的 B 树索引不大于单个 integer 上的一个(8 字节通常是索引元组的最小值 "payload")。其他更大的数据类型会产生额外的差异。

  • 如果 review 收到对其中一列 (account_id, product_id) 的许多更新,这些更新将级联到所有基于这两列的引用 table。增加写入成本,膨胀多个 table 和索引。如果它级联到宽行或许多引用行,成本可能会增加显着。所有这些 都可以 通过代理 PK 来避免 - 如果关系设计实际上应该以这种方式工作的话。

如果 review 涉及许多具有连接的查询,连接两列而不是仅连接一个列编写起来更乏味且成本​​稍高。同样,对于更大的数据类型更是如此。

也就是说,如果您有 none 以上(或类似),请查看 Laurenz 的回答。

权衡实际成本,而不是宗教信仰。