对于外键设计,增加ID与全文键的权衡是什么?


8

在许多关系数据库设计中,其他表中都有引用的字段。

例如,考虑具有唯一用户名的用户表和存储地址数据的第二个表。

我会说的一种可能的布局是常用方法,因为我在大多数软件中都观察到了这种布局,就是使用像这样的自动增量ID:

Table users
===========
userId int primary auto_increment
userName varchar unique

Table adressdata
==========
userId int references users.userId
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userId,adress_type))

这就是我过去经常这样做的方式,也是我在大多数情况下所看到的方式。

另一种方法是:

Table users
===========
userName varchar primary

Table adressdata
==========
userName varchar references users.userName
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userName,adress_type))

在这里,我们还将完整的用户名存储在adressdata表中。

对我来说,它具有以下优点:

  • 您可以直接从表中选择用户名,而无需将其连接到另一个表。在此示例中,从应用程序的角度来看,这可能不太重要,但这仅是示例。

  • 在主/主复制环境中扩展数据库可能会更容易,因为不存在auto_increment冲突。

但也有缺点:

  • 第二张表中字段的索引和数据(但更相关的可能是索引)的空间要求更高。
  • 用户名的更改将需要传播到所有表,这比仅在一个表中进行更改并保留ID更为耗资源。

在我看来,使用文本字段并且不使用增量ID更加容易,并且这种折衷是最小的,并且在大多数应用程序中是不相关的。

当然,某些对象按其性质用递增编号标识(例如,论坛帖子应收到递增编号,因为可能没有其他唯一字段,例如标题等)。

但是在开始以完全不同的方式设计数据库布局之前,我想知道是否有我没有想到的东西。

  • 有没有最佳做法?

  • 是否存在我没​​有想到的利弊,并且以后可能会产生影响?

  • 您如何亲自设计有关以上几点的数据库?为什么?

Answers:


3

我建议使用id而不是用户名,因为如果您开始在多个表中将用户名用作联接列,则必须记住要更新所有用户名。

users表的外键成为表的主键,addressdata并且主键必须保持稳定。最好不要更改主键字段。创建记录时,主键必须存在,并且在记录的整个生命周期内都必须保持不变。

如果您想获得进一步的见解很棒的主键辩论是一篇很棒的文章。


2

我坚决参加“不要使用自然键”阵营。那是因为我已经看到了当它们被更新并且几乎所有涉及任何种类名称的自然键都被更新时系统上的困难程度。

数据库经过优化以使用联接。是的,您可以使用自然键来保存一些联接,但是当您需要更新1,000,000条记录时,性能会受到影响,因为一组自然键发生了变化(甚至取决于发生的情况)可能会造成严重的混乱。

我只会在两种情况下使用自然键:

  1. 如果可以肯定保证密钥不变(请考虑汽车VIN号码),并且
  2. 如果它永远不会被重复使用(甚至电话号码和电子邮件之类的独特内容也不是PK的候选对象,因为当有人停止使用它们时,它们会被重新使用)。

当然,所有太多本来应该唯一的自然键也不是。如果您担心复制,则可以使用GUID。


1

Wikipedia上有关替代键的文章有一些有趣的地方:

  • 唯一标识实体的属性可能会更改,这可能会使自然复合键的适用性失效。 ”例如,以后对用户名的限制可能会在使用自然键时使现有键失效,user name而这不会影响合成键。
  • 当行存在时,代理键不会更改。 ”因此,您不需要(手动或自动)将键更改层叠到引用表。
  • 生成的代理键的值与连续保存的数据的真实含义没有关系 ”这会使审核变得困难。

我相信,细心的读者可以找到其他要考虑的方面。


好答案。许多自然键都有变化的趋势。这使它们不适合用作外键的键。有许多理由适合更改用户的用户ID。
BillThor

1

我将从我的经验中发布,这可能与各种DBA可能建议的有很大不同。在为各种项目设计数据库时,我主要面向性能和可维护性的混合。

永远不会使用自然键作为主键。特别是如果我使用MySQL / InnoDB。我仍然没有看到使用自然键的任何好处,通常我看到的都是性能问题,如果没有的话。我之所以用粗体表示“从不,从不”,仅仅是因为自然键曾经用来为我的项目创建性能猪。代理(整数)始终是一个更好的选择。有些人可能不同意,但是我们生活在一个性能确实在理论中发挥作用的世界。

当涉及到JOIN时,我不会不惜一切代价避免它们,但我倾向于对其进行优化。我尝试尽可能地滥用InnoDB的聚集索引(主键)。如果通过PK执行JOIN,则它们将非常快。我也倾向于避免没有意义的FK。老实说,在链接用户及其地址信息时,我不太在意数据完整性。将发票链接到用户项目时,我会强制执行。引用完所有内容后认为过度使用FK是一个过大的任务,也是一个噩梦,认为这是在整个地方保持联系的好方法。在某个时间点,事情需要改变,而当MySQL开始不断出现错误150并抱怨时,您只想回家。

您还提到了复制并避免由于auto_increments的性质而发生冲突。我有一个项目,其中有大量存储产品销售信息的数据库,而数据库的数量是可变的。每天,数据库都被复制到一个“主”数据库中,该数据库用于运行报告。我避免PK冲突的方法是通过从auto_increment部分和另一个INT部分构成复合主键来表示记录的来源。这样一来,我可以跟踪事物的来源,并且没有丢失任何东西(产品具有相同的ID,只是位置标识符已更改)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.