代码之家  ›  专栏  ›  技术社区  ›  bbadour

主键的设计标准是什么?

  •  8
  • bbadour  · 技术社区  · 14 年前

    选择好的主键、候选键和使用它们的外键是一项极其重要的数据库设计任务——与科学一样重要。设计任务有非常具体的设计标准。

    标准是什么?

    12 回复  |  直到 14 年前
        1
  •  15
  •   BradC    14 年前

    考虑主键的标准是:

    • 唯一性
    • 不可约性 (键的任何子集都不能唯一标识表中的行)
    • 简单性 (这样关系表示和操作就更简单了)
    • 稳定性 (不应经常更改)
    • 熟悉程度 (对用户有意义)
        2
  •  18
  •   OMG Ponies    14 年前

    什么是主键?

    主键是唯一标识数据行/记录的东西。它也可以是多个列,称为复合列。

    改变的能力

    因为主键经常用于外部引用,所以它应该尽可能稳定。数据库中的所有数据都是可变的,前提是有人正在连接具有适当权限的帐户。这就是为什么数据库提供了定义删除时层叠和更新时层叠的能力——在不禁用约束的情况下同步引用依赖项。

    自然的还是人工的/替代的?

    理想情况下,你需要一把自然钥匙。自然键是唯一标识正在建模的实体的现有数据。例如,美国各州的缩写是一个很好的自然键,因为缩写是一致的,每个人都知道:

    US_STATE_PRIMARY_KEY  US_STATE
    -------------------------- 
    AL                    Alabama
    AK                    Alaska
    AZ                    Arizona
    AR                    Arkansas
    CA                    California
    

    不要太努力去寻找一把天然钥匙。它们很少存在。美国的州名不太可能会改变,但这是合理的。

    实际上,主键通常是人工的(通常由数据库功能生成)。这些通常是数字或guid,它们被认为是人工的,因为它们本身——没有任何东西可以将它们的价值与它们唯一标识的信息联系起来。销售收据总是有编号的,因为这并不是自然的,它也用于审计——收据编号的差异会引起怀疑。为了演示任意编号的方式,这里是US状态表,但使用整数作为主键列,US状态代码:

    US_STATE_PRIMARY_KEY  US_STATE
    -------------------------- 
    100                   Alabama
    101                   Alaska
    102                   Arizona
    103                   Arkansas
    104                   California
    

    不需要从一开始值;一些商店将其用作阻止SQL注入的安全措施。该值是根据州名的字母顺序排列的,但不能保证这一点。但与自然键不同的是,如果状态名发生更改,则只需更新一列。

    单柱vs复合柱

    理想情况下,一列将是主键,但要根据手头的数据做出决定——不要仅仅为了拥有一列而组合列。如果将数据放在一起,可以使用字符轻松地分隔数据(尽管这样做的操作无法利用索引(如果存在的话)。

    性能

    从性能的角度来看,整数是最好的,因为它们提供了一个合适的值范围,与五个或更多字符的varchar相比,使用的字节数很小。

        3
  •  8
  •   APC    14 年前

    数据库设计从概念数据模型(如实体关系图)开始,最后是一个或多个数据库模式。实体映射到表;在此过程中,一个实体可以拆分为多个表,多个实体可以合并到一个表中,并可能出现新的表(例如,实现多对多关系的交叉表)。

    在ERD中,实体具有主键。这些是自然键,也就是实体的属性。对于个人实体,它可能是SocialSecurityNumber。对于订单实体,如果它可能是发票实体的orderRef,则它可能是invoiceno。在第一种情况下,它是一个真实的标识符;在第二种情况下,它是一个丑陋格式的智能钥匙(2010/def/000023);在第三种情况下,它是一个单调递增的数字,因为这正是当前基于纸张的系统所使用的。

    自然的钥匙可以是奇幻的。我曾经做过一个数据库设计,在这个数据库设计中,分析人员用一个键(全名、地址、性别、出生日期、区别特征)指定了客户实体,基于相同姓名、出生日期和性别的两个人可以住在同一个地址。

    实体主键的特征是:

    • 独特的
    • 熟悉的
    • 稳定(假定)
    • 最小(一个或多个属性,但必要时尽可能少)

    当涉及到数据库表的主键时,自然键并不总是合适的。

    有很多原因不使用ssn作为物理主键。保护公民的个人数据实际上是最重要的,但个人的数据也会发生变化。主键应不变。

    智能钥匙是愚蠢的。它们实际上是压缩成单列的复合键。它们最好用单独的列来表示,尤其是因为经常需要搜索键的单个元素。此外,这些键的格式也可以更改。

    一般来说,复合键作为主键是一个难题,因为我们必须将多个列作为外键级联。当子项的主键被定义为父项主键中的序列号时,这种情况会加剧。有一些系统存在依赖表,当它们自己只有很少的两个数据列时,这些依赖表从父表继承一个九列的外键。有时这种继承可能很有用,但大多数情况下只是一个麻烦。

    实体主键的特征是:

    • 独特的
    • 适当(无意义)
    • 保证稳定性
    • 最小值,通常为单列(交叉表除外)

    因此,除非候选键是无意义的标识符(如invoiceno),否则表应该有一个合成键(又称代理键)。根据您的需要,这可以是一个单调递增的数字或一个guid。关于交集表,如果它们没有其他属性或依赖表,那么用合成主键替换复合主键(也称为复合键)就没有价值。

    关键是:我们仍然 强制使用候选键 . 这意味着对父表中的列(ssn、orderref)应用唯一约束。这是因为合成键唯一地标识表中的行,而不是唯一地标识数据。


    关于熟悉度

    熟悉是卷曲的。当我们在概念数据模型中识别主键时,它是一个重要的考虑因素,但在数据库设计中,它就不那么有用了。

    在commnet@bbadour中,提供了两个对比示例:

    {3296013,840082470,Bob Badour,745} versus {840082470,Bob Badour,PE,CA}  
    

    并提出问题:

    3296013所取得的成绩在840082470年之前还没有达到,这恰好是我在加拿大任何一所或每一所高中学习成绩的主要关键。

    嗯,840082470就像一个发票号码。它本身就是一个毫无意义的数字串。如果我们正在设计的系统属于加拿大高等教育领域,那么它当然可以作为候选密钥。但是,由于它显然是一个外部中央系统所拥有的密钥(请原谅我不理解加拿大的学术系统),因此对SSN作为主要密钥的一些异议是开放的。我们依靠外部系统来确保唯一性、稳定性和验证识别。

    至于 七百四十五 对战 CA体育 这显然是错误的。加拿大邮政中“爱德华王子岛”的缩写和“加拿大”的iso有向图标识了两个不同的信息,它们来自不同的来源,因此它们应该表示为两个单独的列。但让我们关注一下 七百四十五 体育课 成为更好的主键。

    首先,数据库不关心代码使用哪种数据类型来表示“爱德华王子岛”。它只是想要有保证的独特性。

    第二件事是,面向用户的部分系统可能会显示完全扩展的“爱德华王子岛”,在这种情况下,应用程序无论如何都需要执行查找。这是因为同时保存秘鲁或加利福尼亚州地址的系统的用户会欣赏扩展名的清晰性[1]。当然,如果我们超越了少数困难的情况(如状态缩写),那么应用程序在向用户显示代码时应该始终扩展代码。

    因此,使用 体育课 而不是 七百四十五 它使即席查询更容易。

    第三点,如果代码扩展发生更改,我们可能需要区分使用较新版本的记录。如果 745='Prince Edward Island' 746='Prince Edward Is.' 如果我们使用pe作为主键的话。

    第四,有编程方面的考虑。例如,如果应用程序开发人员必须使用Java枚举提供下拉列表,则它们需要数字代码。

    简而言之,自然键的熟悉性不如代理键的实用性有用。

    [1]加拿大人会知道CA代表加拿大。但是莫代表摩洛哥、摩纳哥、摩尔多瓦、黑山、蒙古还是蒙特塞拉特?其实没有一个是澳门。

        4
  •  4
  •   Randolpho    14 年前

    主键是唯一标识实体的键。当您选择主键时,最好的选择几乎总是一个代理键,除了唯一地标识它,它与实体完全无关。

    就是这样。据推测,在一些边缘情况下,主键可能是自然键,但我从未见过有效的。

    我们大多数人使用一个32位的自动递增整数作为主键。另一个很好的选择(在某些情况下)是UUID。

        5
  •  4
  •   nvogel    14 年前

    候选键是一组不可约唯一的属性(不可约意味着在不丢失唯一性属性的情况下,不能从键中删除任何属性)。

    选择要实现的候选键时的其他标准是:简单性、稳定性、熟悉性。

    这三个标准是重要的考虑因素,但不一定是键的基本属性。例如,强制一个经常更改的键可能是可取的,也是相当合理的。例如:用户登录名必须是唯一的,但只要保持唯一,用户可以随意更改。

    主键是候选键。

        6
  •  3
  •   Erwin Smout    14 年前

    嘿。它又开了。来吧。

    (1)选择好的候选键。

    选择候选键不属于数据库设计器。 数据库设计者有责任确保 将强制执行用户通知的唯一性要求。 所以是用户“选择”候选键是什么。

    有两种情况我能想到,放松一下,这很明确。 稍微定位一下。

    一种是如果用户说“视频”或“音频”类型的某个属性(或 其中一些)是独一无二的。实际执行可能是不可行的 设计师有责任指出 用户(因为他也有责任指出 音频和视频内容是一个非常有争议的主题,而且 这些属性值的唯一性,即使系统可以强制执行, 仍然很有可能不具有与用户相同的唯一性 想要)。

    第二个问题是,图片如何被清晰的可能性弄得模糊不清。 逻辑设计都解决了相同的问题。如果d1和d2都是 有效的设计解决了同样的问题,那么情况可能是 用户强制的某个给定的唯一性规则可以使用 键在d1中,但不在d2中。从这个角度来说,“选择候选人 键“可以解释为”选择特定的设计,这样 给定的唯一性规则可以使用键强制执行。但那不是真的 你问的问题。

    (2)选择好的主键。

    不久前,达温提出了这样一个问题:“单身的好理由是什么?” 从其他候选人中选出一位“主要”候选人?. 除了那句话:“建议 在引用 这个RelVa.我怀疑他们没有找到足够的说服力来改变 他们早期的决定是“没有一把钥匙比其他钥匙更独特”。

    但是,假设尽管如此,仍然有一些合理的理由来单挑 我想是用一个特定的键作为“主键”,如下所示 注意事项适用:

    • 使用此主键的可能性或适当性也为, 例如,物理设计中的群集键。
    • 因此,必须改变 一些现有主键的值。高度稳定的关键值 比波动性更大的关键值更可取。
    • 自然使用某种密钥的业务所占的百分比 他们的日常运作。
    • 如果物理编码键值所需的空间是 显著不同的是,哪一个具有最小的编码大小。
        7
  •  3
  •   Carlos M. Calvelo    14 年前

    你对欧文的回答是: “我同意,选择主键仅指定一个候选键作为外键引用的首选项。但是,即使我们完全消除了名称“主键”,设计人员仍然必须选择将哪个候选键传播到另一个关系中以供参考。如果用户用一个不稳定的组合键来标识一个被大量引用的关系,您是否打算暗示设计者没有必要选择一个额外的简单、稳定的键?或者使用简单、稳定的键来引用关系?你的候选人关键部分似乎暗示了这一点。_“8小时前的巴杜尔”

    你最初的问题是关于“主键”。现在您将焦点切换到键和外键。键是一个完整性约束,所以唯一的标准是在一个关系中,一组最小的属性必须是唯一的(唯一性和不可约性)。如果我们将焦点转移到外键上,那么简单性、稳定性和熟悉性是从取消引用关系中的所有候选键中选择的标准。可以有更多的候选键来或多或少地满足这个标准。如果我们看一下熟悉度,一个候选键对于一组用户来说可能非常熟悉,而对于另一个候选键更熟悉的组来说则不是。考虑数据库的不同视图或子模式。第二组用户应选择不同的候选密钥以供参考(作为外键)。如果你坚持使用“主键”,我们每个关系只有一个“主键”,那么我必须问,是什么使一个键比其他键更重要。 我认为不应该使用“主键”这个词。至少在逻辑层面。另外,术语“外键”的选择也不正确(外键不是键,而是引用)。

    因此,我认为欧文关于primary keys的评论非常切题。或者至少这是我对他的解释。

    你同意吗? 如果是这样,您会将原始问题更改为“密钥的设计标准是什么,从可用的候选密钥中选择外键的标准是什么?”? 如果不是,为什么?

    当做, 卡洛斯

        8
  •  2
  •   Paul Mansour    14 年前

    主键是为特殊处理选择的候选键,因此首先我们必须查看候选键的属性。如果一组一列或多列具有以下两个属性,则它是候选键:

    唯一性:候选键必须唯一标识表中的每一行。任何表都不能包含具有相同候选键值的两行。

    不可还原性:从候选键中删除任何列都必须违反uniqness属性。换句话说,候选键中的任何列子集本身都不是候选键。

    如果不存在候选键,有时甚至存在候选键,则通常使用自动递增整数列创建代理键,或者使用其他技术组成代理键。这个代理键现在也是一个候选键。

    在可用的候选键中进行选择并将其中一个指定为主键通常很有用。通常应用的第一个标准是简单地用最少的列指示候选键。然而,还有其他潜在的标准,比如熟悉度,熟悉的值比不熟悉的值更有用,稳定性,稳定的键比容易改变的键更容易麻烦。然而,这些标准在关系模型的范围之外是严格的,经常相互冲突,并且常常被用来处理实现限制。

    我想说,前两个概念“唯一性”和“不可约性”比主键的基本属性更少,而后一个概念“简单性”、“熟悉性”和“稳定性”则更恰当地标记为设计标准,因为它们涉及权衡和主观性。

    为什么选择主键?简单性和熟悉性不仅是在可用候选键中选择的标准,而且也是我们应该选择主键的原因。如果一个表中有多个候选键,那么如果指向该表的所有外键都引用同一个候选键,则简化了操作。此外,选择一个特定的候选键的行为将有助于使其熟悉。

        9
  •  2
  •   Quassnoi    14 年前

    标准是什么?

    PRIMARY KEY 定义实体的东西,只有实体,只有实体。

    • 你可以从外面世界拿走。例如,用于标识星的星目录号(很好的例子),或 SSN 识别一个人(坏榜样)。

      在这种情况下,你依赖外部世界。

      • 所有人都有吗 SSN ?(他们不)。
      • SSN 独特吗?(他们不是)。
      • 可以一 SSN 分配给其他人?(可以)。
    • 您可以在模型内部生成它,使用 AUTOINCREMENT GUIDs 或者什么。

      在这种情况下,您依赖于您自己和您的数据库技能。

      • 你模特里的所有人都有 ID ?(是的,他们有,否则他们不会和 ID NOT NULL )
      • 这些是 ID's 独特的?(是的,他们是 主键 约束解决了问题)。
      • 他们能被分配给其他人吗?(不,它们不能,它们要么是设计不可重复的,要么是自动递增的)。

      或另一组答案:

      • 你模特里的所有人都有 身份证件 ?(不,他们没有,虽然还保留了一些其他信息,但人们的桌子意外地掉了下来)。
      • 这些是 身份证 独特的?(不,我们未能正确合并数据库的两个版本)。
      • 他们能被分配给其他人吗?(是的,我们重置了 自动增量 错了)。

    最重要的是,一个代理密钥是一个永远与你同在的盛宴。你总是可以创建一个代理密钥:地球上没有任何东西可以阻止你声明 自动增量 字段。但到目前为止,并不是所有事物都有某种大家都认同的标识符。

    然而,一把好的自然钥匙不能过分强调。

    Guide Star Catalog 数据库的备份可能比您的更可靠,并且 US 状态码,你总是可以从内存中恢复。

        10
  •  1
  •   Tahbaza    14 年前

    只有一个是真的,为每个表选择一个代理(身份/自动编号)或类似的东西,用户将永远看不到,所以你可以做任何必要的与他们现在和未来的时候,你需要他们。

        11
  •  1
  •   BradC    14 年前

    (不太确定如何解释这个问题。听起来像是一个小测验,或者是从课本上找一个“正确”的答案。我将把这个问题解释为一个更实际的问题,因此我的建议如下。)

    至少在MS SQL的世界中,关于正确主键的讨论不可避免地被关于正确主键的讨论所包围。 聚集索引 一张桌子。两个不 保持不变,但默认情况下它们是相同的,对于许多表来说,使两个表保持不变通常是一个好主意。

    为了在这里进行讨论,必须区分这两个方面:

    主键 是唯一标识行的字段或字段组合。
    聚集索引 表示表的物理顺序的字段或字段组合。(再说一遍,我是在谈论MS SQL Server,不确定其他RDB如何处理这个问题)

    我讨论的其余部分的关键是知道,自从SQL 7.0以来, 聚集索引键 用作所有行的行标识符 非聚集索引 . 这意味着选择一个好的集群密钥的许多相同的标准与选择一个好的主键的标准相同。

    让我们首先看一下一个好的聚集索引的标准(从 Kimberly Tripp's excellent article )聚集索引应为:

    1. 独特的 -否则不能用作其他索引的行标识符
    2. 狭窄的 -此键用于其他索引,因此应尽可能窄
    3. 静态的 -如果键值更改,则引用将变为无效,需要更新
    4. 不断增加 -在添加新行时减少物理表碎片

    很明显,前3个也是主键的良好标准。#4是一个额外的功能,可以随着表的增长减少表碎片。

    一个guid作为主键,尽管很流行,但实际上没有满足其中的两个条件(窄且不断增加)。因此,在大多数情况下,不建议将其作为pk/聚集索引(参见kim's related article here )

        12
  •  -2
  •   Joshua    14 年前

    我要在这里说一些出乎意料的话。

    他们在数据库中教的关于规范化和键的所有内容在选择主键时都是错误的。

    主键在范围查询方面是特殊的,因此,如果您有一个占主导地位的范围查询(即主键),就没有异常。

    如果主范围查询不在候选键上,则最终得到的主键不是为唯一性而强制执行的!这有时被称为聚集索引,这是一个误称,因为没有索引。

    现在,规范化键和候选键都很重要,您将希望至少对其中一些键实施唯一约束。但不要分配主键,因为它是自然键。实际上,这比定义索引和唯一约束要慢。仅基于范围查询定义主键。

    记住,实际上拥有主键没有约束。没有主键的表称为堆表,没有内部顺序或插入顺序的内部顺序。

    编辑:范围查询的定义:
    范围查询是一个按查询排序的查询,或者包含大于或小于运算符。我们感兴趣的是这些查询运行的列。基本思想是范围查询根据一端或两端的边界条件从表中提取数行(数十到数百到数千,但不是全部)。
    还有另一种范围查询,也就是说,您有一个到另一个表的外键,操作是在该外键上选择所有匹配项。这实际上也是一个范围查询,尽管显然不是这样。