【问题标题】:Duplicating / Unnecessary data in a SQL databaseSQL 数据库中的重复/不必要的数据
【发布时间】:2010-02-28 12:33:03
【问题描述】:

在为多个用户设计新的应用程序/数据库时,通常会涉及到一个用于用户管理的表。

该表通常总是有用户名和 ID....

只是为了确认我不是白痴(好吧,你可能仍然这么认为!)我刚刚下载并查看了 MediaWiki 和 PHPBB 的架构,它们也是这样做的。

当我第一次了解关系数据库时,我总是被告知一条重要规则是永远不要复制数据或做任何不必要的事情。

那么,为什么我们的主键是 ID 而不是 Username?

如果它不是唯一的(例如 SO 系列网站),我理解原因,但在这些应用程序中,它是。

我唯一能想到的是使用Select * from xxx where ID="454" 而不是Select * from xxx where name="some_really_long_name" 会更快,或者因为名称很长会大大增加数据库大小。

这些是唯一的原因,还是我在这里遗漏了什么?

【问题讨论】:

  • ....哇...这么多好答案,很难选择正确 - 耻辱您不能标记倍数或给那些加倍努力的人+2...除非其他人回应了一些让其他人陷入困境的东西,我想我会为 Charles Bretana v Donnie 掷骰子......从那里写的东西中学到了很多东西,感谢其他所有提到重命名的人 - 非常有意义,感觉就像一个没有考虑过的白痴。

标签: sql database-design data-modeling


【解决方案1】:

使用整数非智能主键代替唯一文本键的原因:

  1. JOIN 和其他查询的速度。

  2. 能够更改文本键值并保持数据库的完整性,而无需更新引用该键的每个表。

  3. 当您的应用程序必须在内存中构建键值列表时,提高了代码效率并减少了内存开销。

  4. 减小了引用键的表的大小。

【讨论】:

  • 必须选择一个获胜者 - 就像你的答案一样,还有 Charles Bretana 和 OMG Ponies 的答案 - 我会掷骰子,你是 3 和 4。
【解决方案2】:

键有两个不同的目的,一个是防止插入重复的行......这并不意味着数据值都相同,这意味着两行代表相同的现实世界实体。只有有意义的自然键才能做到这一点。
第二个目的是充当依赖表中外键列的目标。
为此,最窄的(最小字节数)键将在与键一起使用并在执行搜索时使用的索引上生成最佳性能。

因此,当自然键由多列组成或非常宽时,有时建议创建第二个备用键或 代理 键用作其他表中 FK 引用的目标。这通常是一个内部创建的值,在数据库中创建,不会暴露在应用程序或系统之外,甚至可能不会暴露在数据库组件本身之外。

如果那是唯一的键,因为它不是有意义的或自然的键,完全不足以确保数据的一致性,因为两行代表相同的实体,并且它们的所有属性仅在无意义的情况下有所不同代理键,仍然可以插入到表中。
因此,在这种情况下,最好将两个键放在桌子上。

除了经常用于提高性能之外,代理键还具有无需更改的额外优势(因为它们没有意义)。想出最好的自然键,准确和唯一地识别实体,永远不需要改变,是一种艺术形式,很容易做得不好。 (SSAN 是一个典型的例子)然后,如果现实世界的实体更改了设计不佳的自然键中使用的任何值,并且您将其用作唯一键(因此在其他地方作为 FK),您将不得不更改数据库中任何地方的值,包括在您将其用作外键的所有其他表中。

【讨论】:

  • +1,太棒了,谢谢!你说自然键——这和唐尼所说的代理键一样吗?
  • 它与代理键相反。
  • @Larry,谢谢,刚刚重读这个 - 看起来我第一次读得有点快......代理键是我多年来一直使用的 - 只是不知道它被称为@ 987654321@ 和自然键是指标准的唯一列?...我从事数据库工作多年,但我“只是继续”我知道需要什么以及在某些地方做什么,只是不总是知道某些事物的术语/定义/名称。
  • @Charles:自然键只是按原样或按惯例存在的键。例如 - 美国州的缩写是一个理想的键,因为 a) 它是独一无二的,并且 b) 每个了解美国各州的人都会知道该缩写。人工(AKA 代理)键与数据没有任何关系 - ID #1234 可以引用任何内容。
  • +1 - 很好的解释。我要补充的唯一另一件事是整数 surrogate 键永远不需要在将其用作 FK 的表中进行更改。如果您需要更改 ID,那么您可以在根表中执行此操作,而不必担心在整个数据库中传播更改。我使用的正是这种系统,尽管我们不鼓励人们更改 ID,但有时必须这样做。
【解决方案3】:

...为什么我们的主键是 ID 而不是 Username?

数据建模的第一条规则是您公开您的密钥。这是因为:

  1. 您希望使您的系统不向用户群显示无法更改的信息。
  2. 存在安全问题:如果您不采取预防措施,现在您的用户可能会被欺骗
  3. 如果您必须迁移到新的数据库、相同的供应商或其他 - 转换应该是无缝的。您可能必须更新引用,但用户会注意到他们昨天是 1234,今天是 100234。人们很难记住创建强密码...
  4. 基于整数的键速度更快,占用的空间更少。这些被称为人工键。
  5. 允许某人更改其用户名是一个不错的功能;当您的系统处理因结婚(或离婚)而更改姓名时,这是必要的。

自然钥匙与人工钥匙

自然密钥只是按原样或按惯例存在的密钥。例如 - 美国州的缩写是理想的键,因为:

  1. 这是独一无二的
  2. 每个了解美国各州的人都会知道该缩写。

人工(AKA 代理)键与数据没有任何关系 - ID #1234 可以引用任何内容。

理论上,尽可能使用人工密钥。因为 ID 1234 可能意味着任何东西,所以当您使用自然键时,无需加入即可知道给定 id 值的含义。实际上,由于性能和自然键都不是很常见 - 使用人工键。

【讨论】:

  • 我喜欢你的回答,但很难只挑出一个获胜者,这是在你、Charles Bretana 和 Larry Lustig 之间......我会掷骰子,你是 5 和 6
  • 谢谢你的回答,但很抱歉,4 赢了。
【解决方案4】:
  1. 用户名可以轻松更改/重命名。这非常有用。
  2. 速度略快
  3. 总体而言,它节省了空间/内存(确实,少量)

PS:不要忘记在username 列上添加unique 约束。

【讨论】:

    【解决方案5】:

    这就是所谓的Surrogate Key。它不是复制数据,而是代替数据。大多数情况下,它的存在只是因为它更容易,尤其是当自然键是多个字段时,然后您必须将其用作另一个表中的外键。

    它们很常见,但有healthy debate 关于它们是否“正确”。就个人而言,我使用它们只是因为它简化了生活。另一个好处是,如果您使用自然键并且有人拼写了该键,那么如果它是外键,您最终不得不跨多个表进行级联更新。由于无法输入代理键(它是系统生成的),因此这绝不是问题。

    【讨论】:

    • +1,太棒了,谢谢! - 我在不知道术语的情况下做了很多工作!
    • 值得注意的是,自然键几乎总是唯一索引,而代理键则作为PK。
    • “数据库用户可能会导致系统生成或删除代理项,但他们无法控制其值,也不会向他们显示其值”,Codd。我认为用户 id 甚至可能在某些应用程序中被用户使用,所以它并不是真正的代理键。有时会有一些特殊的用户 ID,例如这里社区中的 -1。
    【解决方案6】:

    至少有一个原因 - 如果用户名不是主键,您可以廉价地更改它。

    【讨论】:

      【解决方案7】:

      一个关键优势是通过拥有一个单独的 ID,您可以在不破坏任何外键关系的情况下更改用户名。

      此外,使用没有意义的主键是一个很好的 RDBMS 实践——用户名显然是有意义的

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-06
        • 1970-01-01
        • 2010-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-23
        相关资源
        最近更新 更多