0

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

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,
);
4

2 回答 2

2

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

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

唯一会提倡第一个解决方案的人是那些坚信每张表都必须有一个人工生成的数字主键的人,无论如何。实际上,从引用的表中人工生成的两个键的组合也一样好。

于 2019-11-12T22:33:25.247 回答
1

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

如果您要使用其他表中的外键引用该表:

  • 引用表只需要包含单个代理 PK 列作为 FK 引用,它更小、更快、更简单。如果引用表有很多行而review没有,则单个实例可能已经超过了review. 否则,可能有多个实例。对于在许多
    行 中引用的小型查找表,甚至可以考虑代理 PK - 如果这确实有帮助的话。看:smallserial

  • 通常,在引用表的 FK 列上也会有一个索引。您的两个示例integer最适合多列 PK / FK,因为它将索引大小保持在最小。两列上的 B 树索引integer不大于单列上的一个integer(8 字节通常是索引元组的最小“有效负载”)。其他更大的数据类型会产生额外的差异。

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

如果review涉及到许多使用连接的查询,则连接两列而不是一列会更繁琐且成本略高。同样,对于更大的数据类型更是如此。

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

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

于 2019-11-13T00:56:35.273 回答