有一个没有整数主键的数据库表有什么好的理由吗?

时间:2009-03-22 23:12:38

标签: database primary-key

虽然我犯了这种罪行,但在我看来,没有任何充分的理由让一张桌子没有身份字段的主键。

优点: - 无论您是否愿意,您现在可以唯一地识别表中您以前无法做到的每一行 - 如果没有表上的主键,你就无法进行SQL复制

缺点: - 表格的每一行额外32位

例如,考虑需要在数据库的表中存储用户设置的情况。您有一个设置名称列和一个设置值列。不需要主键,但拥有整数标识列并将其用作主键似乎是您创建的任何表的最佳实践。

除了大小之外还有其他原因,每个表不应该只有一个整数标识字段吗?

11 个答案:

答案 0 :(得分:14)

当然,单数据库解决方案中的一个示例是,如果您有一个国家/地区表,使用ISO 3166-1-alpha-2 country code作为主键可能更有意义,因为这是一个国际标准,并且查询很多更具可读性(例如CountryCode = 'GB'而不是CountryCode = 28)。类似的论点可以应用于ISO 4217 currency codes

在使用复制的SQL Server数据库解决方案中,UNIQUEIDENTIFIER密钥更有意义,因为某些类型的复制需要GUID(如果有多个源数据库,也可以更容易避免密钥冲突! )。

答案 1 :(得分:10)

的表格最明显的例子需要代理键是多对多关系:

CREATE TABLE Authorship (
  author_id INT NOT NULL,
  book_id   INT NOT NULL,
  PRIMARY KEY (author_id, book_id),
  FOREIGN KEY (author_id) REFERENCES Authors (author_id),
  FOREIGN KEY (book_id) REFERENCES Books (book_id)
);

在设计标记系统时,我也更喜欢自然键:

CREATE TABLE Tags (
  tag VARCHAR(20) PRIMARY KEY
);

CREATE TABLE ArticlesTagged (
  article_id INT NOT NULL,
  tag        VARCHAR(20) NOT NULL,
  PRIMARY KEY (article_id, tag),
  FOREIGN KEY (article_id) REFERENCES Articles (article_id),
  FOREIGN KEY (tag) REFERENCES Tags (tag)
);

与使用代理“tag_id”键相比,这有一些优势:

  • 您可以确保标记是唯一的,而不会添加多余的UNIQUE约束。
  • 您可以防止两个不同的标记具有完全相同的拼写。
  • 引用标记的从属表已经有标记文本;他们无需加入Tags即可获取文字。

答案 2 :(得分:6)

每个表都应该有一个主键。它是一个整数,GUID还是“设置名称”列并不重要。类型取决于应用程序的要求。理想情况下,如果要将表连接到另一个表,最好使用GUID或整数作为主键。

答案 3 :(得分:3)

是的,有充分的理由。您可以拥有语义上有意义的真实密钥,而不是人工身份密钥。另外,为Many-Many表格分配自动增量主键并不是一个好主意。您可能希望选择GUID。

话虽这么说,我通常使用自动增量64位整数作为主键。

答案 4 :(得分:3)

每个表都应该有一个主键。但它不需要是单个字段标识符。例如,在财务系统中,您可能将日记帐表上的主键设置为日记帐ID和行号。这将为每一行生成唯一的组合(并且日记帐ID将是其自己的表中的主键)

您的主键需要定义如何将表链接到其他表。

答案 5 :(得分:2)

我认为每个表都不需要主键。有时您只想“连接”两个表的内容 - 通过他们的主键。

所以你有一个像users的表和一个像groups的表(每个都有主键),你有一个名为users_groups的第三个表,只有两个列(用户和组)用户和组彼此连接的地方。

例如,user = 3且group = 6的行会将具有主键3的用户链接到具有主键6的组。

答案 6 :(得分:2)

不将主键定义为标识的一个原因是将主键定义为GUID或使用外部生成的值填充。

通常,每个语义上有意义的表应该具有主键,并且这样的键应该没有语义含义。实现多对多关系的连接表本身没有意义,因此它不需要这样的主键(它已经通过其值有一个)。

答案 7 :(得分:1)

要成为正确规范化的表,每行应该只有一个可识别的密钥。许多表已经具有自然键,例如唯一的发票号。我同意,特别是对于存储如此便宜,在所有表上都有自动编号/身份密钥的开销很小,但在这种情况下,这是真正的密钥。

我个人不使用此方法的另一个领域,如果是参考数据,通常我们有描述和值

Code, Description
'L', 'Live'
'O', 'Old'
'P', 'Pending'

在这种情况下,使代码成为主键确保没有重复,并且更易于阅读。

答案 8 :(得分:1)

自然主键和代理主键之间的键差异(对不起)是自然键的值包含信息,而代理键的值不包含。

为什么这很重要?根据定义,自然主键保证是唯一的,但它的值 not 通常保证保持不变。当它发生变化时,你必须在多个地方更新它。

代理键的值没有实际意义,只是用于识别该行,因此永远不需要更改。它是模型的一个特征,而不是域本身。

所以我唯一认为代理键不合适的地方是在一个关联表中,该关联表只包含引用其他表中行的列(大多数多对多关系)。此表携带的唯一信息是两个(或更多)行之间的关联,它已经只包含代理键值。在这种情况下,我会选择一个复合主键。

如果这样的表有包语义,或者带有关于该关联的附加信息,我会添加一个代理键。

答案 9 :(得分:0)

主键总是一个好主意。它允许非常快速和容易地连接表。它帮助外部工具可以读取系统表以进行连接,从而允许技能较低的人通过拖放创建自己的查询。它还使得引用完整性的实现变得轻而易举,从一开始就是一个好主意。

答案 10 :(得分:0)

我确信知道为网络巨头工作的一些非常聪明的人这样做。虽然我不知道为什么他们自己的原因,但我知道2个没有PK表的情况:

  • 导入数据。该表是暂时的。插入和整个表扫描需要尽可能快。此外,我们需要接受重复记录。稍后我们将清理数据,但导入过程需要工作。
  • DBMS中的分析。识别行是没有用的 - 如果我们需要这样做,那么它不是分析。我们只需要一个非关系的,冗余的,可怕的blob,看起来就像一张桌子。我们将通过编写适当的SQL查询来构建汇总表或物化视图。

请注意,这些案例有充分理由成为非关系型的。但通常你的表应该是关系型的,所以......是的,他们需要一个主键。