数据库“密钥/ ID”设计思想,代理密钥,主键等

时间:2009-12-22 19:39:31

标签: sql database-design

所以我最近看到过一些代理密钥的提及,我不确定它是什么以及它与主键的区别。

我一直认为ID是我这样的表中的主键:

Users
    ID, Guid
    FirstName, Text
    LastName, Text
    SSN, Int

但是,维基百科将代理键定义为“数据库中的代理键是建模世界中的实体或数据库中的对象的唯一标识符。代理键不是从应用程序数据派生的< / EM>“。

根据维基百科,看起来ID是我的代理键,我的主键可能是SSN + ID?这是正确的吗?这是一个糟糕的桌子设计吗?

假设表格设计合理,那么对于那些数据没有任何独特之处的表格,这样的事情是不是很糟糕?

LogEntry
    ID, Guid
    LogEntryID, Int [sql identity field +1 every time]
    LogType, Int
    Message, Text

7 个答案:

答案 0 :(得分:12)

不,您的ID既可以是代理键(也就是说它不是“源自应用程序数据”,例如人工密钥),它也应该是您的主键。 / p>

主键用于唯一且安全地标识表中的任何行。它必须是稳定的,唯一的,而且是非空的 - “人工”ID通常具有这些属性。

我通常建议不要使用“自然”或真实数据作为主键 - 不是真的 150%确定它从不去更改??例如,每当女性结婚(或离婚)时,瑞士相当于SSN的变化 - 几乎不是理想的候选人。它不能保证是独一无二的......

为了免除所有这些悲伤,只需使用系统定义,唯一且永不改变的代理(人工)ID,并且永远不会有任何应用含义(除了作为您的唯一ID)。

Scott Ambler在这里有一篇非常好的文章,其中包含所有各种键的“词汇表”及其含义 - 您将找到自然,代理,主键和其他一些。

答案 1 :(得分:7)

首先,Surrogate键是在数据库中人工生成的键,作为表中每行的唯一值,并且对表中的任何其他属性没有任何依赖性。

现在,短语主键是一个红色的鲱鱼。密钥是主密钥还是备用密钥并不意味着什么。重要的是密钥的用途。密钥可以提供两个功能,这些功能彼此之间不相容。

  1. 他们首先,以确保数据的完整性和一致性!表中的每一行表示定义用于保存数据的表的任何实体的实例。否 代理 密钥 定义 永远 执行此功能。只有设计合理的自然钥匙才能做到这一点。 (如果你拥有的只是一个代理键,你可以随时添加另一行,其他所有属性与现有行完全相同,只要你给它一个不同的代理键值)。
  2. 其次,它们用作其他表中的外键的引用(指针),这些表是具有主键的表中实体的子实体。一个自然键,(特别是如果它是多个属性的复合)对于这个函数来说不是一个好的选择,因为它意味着A)所有子表中的外键也必须是复合键,使它们非常宽,从而降低所有约束操作和SQL连接的性能。和B)如果在主表中更改了键的值,则需要在每个表上执行级联更新,其中值表示为FK。
  3. 所以答案很简单...... 始终(无论您关心数据完整性/一致性的地方)都使用自然键,并在必要时使用两者!当自然键是复合,或长或不够稳定时,添加备用代理键(例如,自动递增整数),以用作子表中FK的目标。但是存在丢失表的数据一致性的风险,请勿从主表中删除自然键。

    为了让这个晶莹剔透,让我们举个例子吧。 假设您有一个包含银行账户的表...自然密钥可能是银行路由号码和银行账号。为避免在事务表中的每个事务记录中使用此双复合键,您可能决定在BankAccount表上放置一个人为生成的代理键,该表只是一个整数。但你最好保持自然的钥匙!如果你没有,如果你没有复合自然键,你可以很容易地在表格中得到两行,如下所示

    id  BankRoutingNumber BankAccountNumber   BankBalance
     1     12345678932154   9876543210123       $123.12
     2     12345678932154   9876543210123    ($3,291.62)
    

    现在,哪一个是对的?

    从下面的评论来看,有什么好处能够“识别 ”?在我看来,没有任何好处,因为我们需要能够识别出行代表的 银行帐户 标识行仅对内部数据库技术功能很重要,例如查询中的连接或FK约束操作,如果/必要时,它们应该使用代理键,而不是自然的键。

    你说得对,自然键的选择不当,有时甚至是自然键的最佳选择,可能不是真正独特的,或者保证可以防止重复。但是任何选择都比没有选择更好,因为它至少会阻止选择作为自然键的属性中相同值的重复行。通过适当选择关键属性可以将这些问题保持在最低限度,但有时它们是不可避免的,必须加以处理。但这样做仍然比允许不正确的不准确或冗余数据进入数据库更好。

    关于“易用性”如果您使用自然键的所有方法是约束重复行的插入,并且您使用另一个,代理,键作为FK约束的目标,我看不出任何容易使用问题。

答案 2 :(得分:4)

数据库纯粹主义者全神贯注于代理键的原因是,如果使用不当,它们可能允许数据重复,这是良好的数据库设计意味着消除的罪恶之一。

例如,假设我有一个邮件列表的电子邮件地址表。我希望它们是独一无二的,对吗?拥有相同电子邮件地址的2,3或n个条目毫无意义。如果我使用email_address作为我的主键(这是一个自然键 - 它作为数据独立于您创建的数据库结构而存在),这将保证我的邮件中永远不会有重复的电子邮件地址名单。

但是,如果我有一个名为id的字段作为代理键,那么我可以拥有任意数量的重复电子邮件地址。如果存在10行相同的电子邮件地址,则会变得很糟糕,所有这些都在其他列中具有冲突的订阅信息。哪一个是正确的,如果有的话?没办法说出来!在那之后,您的数据完整性就会受到影响。没有办法修复数据,而是逐个查看记录,询问人们哪些订阅信息真正正确等等。

非纯粹主义者之所以想要它,是因为它可以很容易地使用标准化代码,因为您可以依赖于引用具有整数值的单个数据库行。如果你有一个自然键,比如set ( client_id, email, category_id ),那么程序员就会讨厌这个实例的编码!它打破了基于类的编码的封装,因为它要求程序员具有对表结构的深入了解,并且删除方法可能对每个表具有不同的代码。呸!

很明显,这个例子过于简化了,但它说明了这一点。

答案 3 :(得分:3)

哇,你用这个问题打开了一堆蠕虫。数据库纯粹主义者会告诉你永远不要使用代理键(就像你上面的那样)。另一方面,代理键可以带来一些巨大的好处。我一直都在使用它们。

在SQL Server中,代理键通常是SQL Server为您生成的自动增量标识值。它与存储在表中的实际数据无关。与此相反的是自然键。一个例子可能是社会安全号码。这确实与存储在表中的数据有关。自然键有一些好处,但是,IMO,使用代理键的好处超过了自然键。

我注意到在您的示例中,您有一个主键的GUID。您通常希望远离GUIDS作为主键。它们很大,很大,通常可以随机插入到您的数据库中,导致严重的碎片。

兰迪

答案 4 :(得分:1)

用户表

使用Guid作为Users表的主键完美

LogEntry表

除非您计划将LogEntry数据公开给外部系统或将其与其他数据库合并,否则我只需使用递增int而不是Guid作为主键。它更容易使用,并将使用稍微减少的空间,这可能在几年的巨大日志中显着。

答案 5 :(得分:0)

  • 主键是你做的任何事情。无论您定义什么,主键都是主键。通常是一个整数ID字段。
  • 代理键也是此ID字段。它是自然键的代理,它定义了应用程序数据的唯一性。

将整数ID作为主键(即使它并不意味着什么)背后的想法是用于索引目的。然后,您可能会将自然键定义为表上的唯一约束。通过这种方式,您可以获得两全其美的效果。使用您的ID字段快速编制索引,每行仍保持其自然唯一性。

也就是说,有些人只是使用自然键发誓。

答案 6 :(得分:0)

实际上有三种关键要谈。主键是用于唯一标识表中每一行的内容。代理键是使用该属性创建的人工键。自然键是从实际真实数据中获得的主键。

在某些情况下,自然键可能不实用,因此可以创建代理键以用作外键等。例如,在日志或日记中PK可能是日期,时间和全文条目(如果可以在同一时间添加两个条目)。显然,每次想要识别行时使用所有这些都是一个坏主意,因此您可能会创建一个“日志ID”。它可能是一个序号(最常见的),也可能是日期加上一个序号(如20091222001),也可能是其他的。一些自然键可以作为主键使用,例如车辆VIN号码,学生ID号码(如果它们不被重复使用),或者在连接表格的情况下,两个表格的PK被连接。

这只是表键选择的概述。有很多东西需要考虑,虽然在大多数商店你都会发现它们一样,“为每个表添加一个标识列,这是我们的主键”。然后你就会得到所有与之相关的问题。

在您的情况下,我认为您的日志项的LogEntryID似乎是合理的。 ID是用户表的FK吗?如果没有,那么我可能会质疑同一个表中的ID和LogEntryID是多余的。如果是,那么我将名称更改为user_id或类似的东西。