Database design 支持表上的自然键与代理键
我读过很多关于自然主键和代理主键之争的文章。 我同意使用代理键来标识其内容由用户创建的表的记录 但是在支持表的情况下,我应该使用什么? 例如,在一个假设的表“orderStates”中。 此表中的值不可编辑(用户无法插入、修改或删除此值) 如果使用自然密钥,则将具有以下数据:Database design 支持表上的自然键与代理键,database-design,primary-key,surrogate-key,natural-key,Database Design,Primary Key,Surrogate Key,Natural Key,我读过很多关于自然主键和代理主键之争的文章。 我同意使用代理键来标识其内容由用户创建的表的记录 但是在支持表的情况下,我应该使用什么? 例如,在一个假设的表“orderStates”中。 此表中的值不可编辑(用户无法插入、修改或删除此值) 如果使用自然密钥,则将具有以下数据: TABLE ORDERSTATES {ID: "NEW", NAME: "New"} {ID: "MANAGEMENT" NAME: "Management"} {ID: "SHIPPED" NAME: "Shipped"
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"}
如果使用代理密钥,则将具有以下数据:
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;
每次我必须将订单移动到新状态时,都会发生同样的情况
那么,在这种情况下,选择一种键类型而选择另一种键类型的原因是什么?如果我理解正确,您的第一个示例显示表的主键是字符串(varchar),而在第二个示例中,主键是整数。主键可能是另一个表中的外键 显然,存储整数比存储varchar占用更少的磁盘空间,尤其是在必须为最长的varchar(在您的例子中是“management”)分配空间的情况下。我认为整数索引比字符串索引更快(索引占用的空间也更小) 第一个示例的主键和“name”字段具有相同的值;虽然更改名称不会更改主键(因此不会对使用“OrderState”作为外键的表产生影响),但会出现逻辑断开-您可以将主键“name”作为主键,而将值“Person”作为主键 通常编写查询,如
select orders.ordname
from orders
inner join orderstatus on orders.status = orderstatus.id
where orderstatus.name = 'NEW'
尽管说实话,我还是会使用一个标志字段来显示状态是否表示初始“新建”状态,而不是检查状态的名称——即使更改了名称,状态仍然是初始状态
您可以使用生成器提供保证唯一的密钥,而如果使用“自然”密钥,则必须检查碰撞。答案是:视情况而定
在代码中更改顺序状态的示例中,问问自己为这些状态创建常量的可能性有多大(例如,为了避免拼写错误)。如果是这样的话,两者将实现相同的目标 在通过表单提交新订单状态的情况下,您可以使用自然键或代理键构建可能值的下拉列表(例如),没有区别 当您在订单表上执行查询并希望打印每个订单的状态时,情况会有所不同。拥有一个自然键可以避免进行另一个连接,这会有所帮助(尽管有点) 就存储和查询性能而言,在大多数情况下,代理键分别更小和更快(取决于表大小) 但话虽如此,它只是需要仔细考虑。就我个人而言,我觉得代用钥匙已经成为一种教条;许多开发人员将在所有表中使用它们,建模软件将在创建表时自动添加它们。因此,你可能会对你的选择有不同的反应,但没有硬性规定禁止你使用它们;明智地选择:)简而言之:
- 自然键可能会减少接合1
- 但也需要更多的空间2(因此会影响缓存性能3)
- 层叠更新
- 集群
- 菱形的附属物等
1个自然键将通过FK迁移到“main”表中,因此如果需要将其与主表行组合在一起,可以完全避免连接。顺便说一句,如果你需要一个不同的连接(为了获得一个非键),你将无法用这种方式消除它 2“main”表可能很大,在这种情况下,存储许多字符串(对于迁移的自然键)比存储许多int(对于迁移的代理项)节省空间。如果主表很小,那么无论哪种方式,它几乎都不重要
3行“更胖”,因此单个数据库页面中容纳的行更少。缓存通常是在页面级别实现的。“在您更改代码中的顺序状态的示例中,问问自己,您为这些状态创建常量的可能性有多大(例如,为了避免拼写错误)。如果是这样,两者都可以完成相同的任务。”这一点很好。现在我正在使用带有键值的enum。我理解,但在这种情况下,用户不能编辑OrderStatus的值。因此,不存在重复的问题。