在设计表时,我养成了一个习惯,即有一个唯一的列,并将其作为主键。这可以通过三种方式实现,具体取决于需求:

自动递增的标识整数列。 唯一标识符(GUID) 短字符(x)或整数(或其他相对较小的数字类型)列,可作为行标识符列

数字3将用于相当小的查找,主要是读取表,这些表可能有一个唯一的静态长度字符串代码,或一个数值,如年或其他数字。

在大多数情况下,所有其他表都有一个自动递增的整数或唯一标识符主键。

问题:-)

我最近开始使用一些数据库,这些数据库没有一致的行标识符,而且主键目前聚集在各个列之间。一些例子:

datetime /字符 datetime /整数 datetime / varchar 字符/ nvarchar / nvarchar

这有有效的理由吗?我总是为这些情况定义一个标识符或唯一标识符列。

此外,还有许多根本没有主键的表。如果有的话,合理的理由是什么?

我试图理解为什么桌子被设计成这样,对我来说,它似乎是一个很大的混乱,但也许有很好的理由。

第三个问题在某种程度上帮助我解析答案:在使用多个列组成复合主键的情况下,与代理/人工键相比,这种方法是否有特定的优势?我主要考虑的是性能、维护、管理等方面。


当前回答

如果你真的想阅读关于这个古老争论的所有内容,可以在Stack Overflow上搜索“自然键”。你应该能拿到几页结果。

其他回答

以下是我拥有25年以上开发经验后得出的经验法则。

所有表都应该有一个单列主键auto 增量。 将它包含在任何意味着可更新的视图中 主键在应用程序上下文中不应该有任何意义。这意味着它不应该是SKU、帐号、员工id或对应用程序有意义的任何其他信息。它只是一个与实体相关联的唯一键。

主键由数据库用于优化目的,应用程序除了用于标识特定实体或与特定实体相关外,不应该使用主键。

始终使用单一值主键使得执行upsert非常简单。

Favor multiple indices on single columns over multi-column indices. For example, if you have a two column key, favor creating an index on each column over creating a two column index. If we create a multi-column key on firstname + lastname, we can't do indexed lookups on lastname without providing a firstname as well. Having indices on both columns allows the optimizer to perform indexed lookups on either or both columns regardless of how they are expressed in your WHERE clause. If your tables are massive, explore partitioning the table into segments based on the most prominent search criteria. If you have a table that has a significant number of Id fields in it, consider removing all except the primary key to a single table which has an id (PK), an org_id (FK to original table) and an id_type column. Create indices for all columns on the new table and relate it to the original table. In this manner, you can now perform indexed lookups of any number of ids using only a single index.

对我来说,自然键和人工键的区别在于数据库中需要多少业务逻辑。社会安全号码(SSN)就是一个很好的例子。

“我的数据库中的每个客户都将而且必须有SSN。”搞定,把它设为主键,搞定。只要记住,当你的业务规则改变时,你就完蛋了。

我自己不喜欢自然键,因为我有改变业务规则的经验。但是如果您确定它不会改变,那么它可能会阻止一些关键的连接。

这只是对一些经常被忽视的东西的额外评论。有时不使用单个代理键作为主键对子表有好处。假设我们有一种设计,允许您在一个数据库中运行多个公司(可能是一个托管解决方案,或者其他什么)。

假设我们有这些表和列:

Company:
  CompanyId   (primary key)

CostCenter:
  CompanyId   (primary key, foreign key to Company)
  CostCentre  (primary key)

CostElement
  CompanyId   (primary key, foreign key to Company)
  CostElement (primary key)

Invoice:
  InvoiceId    (primary key)
  CompanyId    (primary key, in foreign key to CostCentre, in foreign key to CostElement)
  CostCentre   (in foreign key to CostCentre)
  CostElement  (in foreign key to CostElement)

以防最后一点说不通,发票。CompanyId是两个外键的一部分,一个指向CostCentre表,另一个指向CostElement表。主键是(InvoiceId, CompanyId)。

在这个模型中,不可能搞砸并引用来自一个公司的CostElement和来自另一个公司的CostCentre。如果在CostElement和CostCentre表上使用一个代理键作为主键,并且在Invoice表中没有外键关系,那么它就是。

搞砸的机会越少越好。

表应该一直有一个主键。如果没有,它应该是一个自动递增字段。

有时人们会省略主键,因为他们要传输大量数据,这可能会减慢(取决于数据库)进程。但是,它应该加在它之后。

一些关于链接表的评论,这是正确的,这是一个例外,但是字段应该是FK以保持完整性,并且在某些情况下,如果链接中的重复没有被授权,这些字段也可以是主键…但是要保持简单的形式,因为异常在编程中经常出现,所以应该提供主键来保持数据的完整性。

如果有天然钥匙,通常是最好的。因此,如果datetime/char唯一地标识了行,并且这两部分对行都有意义,那就太好了。

如果只有datetime是有意义的,并且只是附加了char以使其唯一,那么您不妨使用一个identify字段。