这里有什么更好的 - 单列或多列主键?

Joh*_*and 2 postgresql database-design best-practices primary-key

假设您有一张桌子groups和一张桌子item。每个项目都属于一个组。它是该群体的固有组成部分。一个项目不能存在于一个组之外,也不能移动到另一个组中。

当试图决定item表的主键时,我应该使用什么?

我应该像这样组成一个人工全局序列键:

CREATE TABLE items
(
    item serial PRIMARY KEY,
    group integer NOT NULL REFERENCES groups(group),
);
Run Code Online (Sandbox Code Playgroud)

...或者我应该使用复合键和每组项目序列,如下所示:

CREATE TABLE items
(
    group integer NOT NULL REFERENCES groups(group),
    item integer NOT NULL,

    PRIMARY KEY(group, item)
);
Run Code Online (Sandbox Code Playgroud)

我更倾向于第二种解决方案的原因是帖子 URL 将始终显示组项目,因此将它们都作为复合主键是有意义的。在第一种解决方案的情况下,URL 包含多余的信息,因为组 ID 已经可以单独从项目 ID 中推导出来。但是,URL 结构是给定的,不能更改。

第二种解决方案的缺点是您必须管理每个组的序列(即每个组的每个项目整数应从 0 开始)。

在最佳实践、规范化和性能方面哪个更好?或者这只是品味问题?

Erw*_*ter 5

这在很大程度上是品味和风格的问题。更重要的是:特定的要求和一致的约定。但是,这个通用建议有很好的理由:

CREATE TABLE item (
    item_id serial PRIMARY KEY,
    grp_id  integer NOT NULL REFERENCES grp(grp_id)
);
Run Code Online (Sandbox Code Playgroud)
  • 如果你有一个item_id,最好让它独一无二,最好是一个代理主键,对数字本身没有任何特定含义。这很便宜而且用途广泛。每组(非per-row)连续剧通常是昂贵的、毫无意义的努力。如果您希望每组无间隙编号,请添加某种等级列或row_number()在视图中使用。如果可以避免,请不要依赖无间隙编号。迟早你将不得不删除或移动项目。

  • 具有遵循命名约定的单列主键便于维护(除非您有明显的自然pk)。

  • 不要group用作标识符。它是一个保留字。即使这些只是象征性的名称。

  • 如果您通过 查询grp_id,请添加另一个索引:

    CREATE INDEX item_foo_idx ON item (grp_id, item_id);
    
    Run Code Online (Sandbox Code Playgroud)

    您可能希望将其UNIQUE INDEX作为文档,但这是多余的,因为item_id它已经是独一无二的。对于两个整数列,多列索引与 just 上的索引一样大,grp_id并且似乎在某些用例中您需要这两列,因此有可能使用覆盖索引。这应该是最佳的。这里有更多理由:
    复合索引是否也适用于第一个字段的查询?