3

我已经阅读了许多关于自然主键与代理主键之间之争的文章。我同意使用代理键来识别其内容由用户创建的表的记录。

但是在支持表的情况下我应该使用什么?

例如,在假设的表“orderStates”中。此表中的值不可编辑(用户不能插入、修改或删除此值)。

如果使用自然键将有以下数据:

TABLE ORDERSTATES
{ID: "NEW", NAME: "New"}
{ID: "MANAGEMENT" NAME: "Management"}
{ID: "SHIPPED" NAME: "Shipped"}

如果我使用代理键将有以下数据:

TABLE ORDERSTATES
{ID: 1 CODE: "NEW", NAME: "New"}
{ID: 2 CODE: "MANAGEMENT" NAME: "Management"}
{ID: 3 CODE: "SHIPPED" NAME: "Shipped"}

现在让我们举个例子:用户输入一个新订单。

在使用自然键的情况下,在代码中我可以这样写:

newOrder.StateOrderId = "NEW";

每次我有一个额外的步骤时,都使用代理键。

stateOrderId_NEW = .... I retrieve the id corresponding to the recod code "NEW"

newOrder.StateOrderId = stateOrderId_NEW;

每次我必须将订单移动到新状态时,都会发生同样的情况。

那么,在这种情况下,选择一种密钥类型而不是另一种的原因是什么?

4

3 回答 3

2

答案是:视情况而定。

在您更改代码中的订单状态的示例中,问问自己为这些状态创建常量的可能性有多大(例如,为了避免拼写错误)。如果是这样,两者都将完成相同的任务。

在通过表单提交新订单状态的情况下,您将使用自然键或代理键构建可能值的下拉列表(例如),没有区别。

当您对订单表进行查询并希望打印每个订单的状态时,情况会有所不同。拥有一个自然键将避免需要进行另一个连接,这会有所帮助(尽管有点)。

在存储和查询性能方面,代理键在大多数情况下分别更小和更快(取决于表大小)。

不过说了这么多,还是要慎重考虑。我个人觉得代理键已经成为一种教条。许多开发人员会在他们的所有表格中使用它们,建模软件会在创建表格时自动添加它们。因此,您可能会对您的选择产生不同的反应,但没有硬性规定禁止您使用它们;做出明智的选择 :)

于 2012-10-05T16:12:17.953 回答
1

简而言之:

  • 自然键可能导致更少的 JOINing 1
  • 但也需要更多空间2(因此会损害缓存性能3)。

这里没有硬性规定。首先确定您是否需要这样的 JOIN,如果需要,是否值得为增加存储而付出代价。做到这一点的唯一方法是测量真实的数据量。

顺便说一句,在自然与替代辩论中还有其他考虑因素,例如……

  • 级联更新,
  • 聚类,
  • 菱形依赖等

...但它们在大多数情况下不适用于您的情况。


1自然键会通过外键迁移到“主”表中,因此如果需要将其与主表行放在一起,则可以完全避免 JOIN。顺便说一句,如果您需要不同的 JOIN (用于获取非密钥),您将无法以这种方式消除它。

2据推测,“主”表很大,在这种情况下,存储许多字符串(用于迁移的自然键)的空间效率低于存储许多整数(用于迁移的代理)。如果主表很小,那么无论哪种方式都无关紧要。

3行“更胖”,因此更少的行将适合单个数据库页面。缓存通常在页面级别实现。

于 2012-10-06T12:02:40.013 回答
0

如果我理解正确,您的第一个示例显示表的主键是一个字符串(varchar),而在第二个示例中,主键是一个整数。主键大概是另一个表中的外键。

显然,存储整数比存储 varchar 使用更少的磁盘空间,特别是因为必须为最长的 varchar 分配空间(在您的情况下,“管理”)。我想按整数索引比按字符串索引要快(索引也会占用更少的空间)。

第一个示例具有相同值的主键和“名称”字段;虽然更改名称不会更改主键(因此对使用“OrderStates”作为外键的表没有影响),但会出现逻辑断开 - 您可以将主键“NAME”作为主键,但将值“Person” '。

通常会编写查询,例如

select orders.ordname
from orders
inner join orderstatus on orders.status = orderstatus.id
where orderstatus.name = 'NEW'

虽然老实说,我会使用一个标志字段来显示状态是否指示初始状态,“新”状态,而不是检查状态的名称 - 即使您更改其名称,状态仍将是初始状态。

您可以使用生成器来提供保证唯一的密钥,而如果您使用“自然”密钥,则必须检查冲突。

于 2012-10-05T15:35:52.487 回答