是自己做唯一约束还是作为主键?
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_id
、account_id
和 product_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 的回答。
权衡实际成本,而不是宗教信仰。
使用这样的 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_id
、account_id
和 product_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 的回答。
权衡实际成本,而不是宗教信仰。