【问题标题】:Is using char as a primary/foreign key a no no?使用 char 作为主键/外键是不是?
【发布时间】:2009-09-14 00:26:56
【问题描述】:

假设有一堆表链接到“国家”或“货币”表。

为了使数据更易于阅读,我希望将带有国家代码(例如 US、GB、AU)和货币代码(USD、AUD)的 CHAR 字段作为这两个表中的每一个的主键,并且所有其他表都将使用此 CHAR 作为外键。

数据库是带有innodb引擎的mysql。

它会导致性能问题吗?这是我应该避免的吗?

【问题讨论】:

    标签: sql mysql database-design data-modeling innodb


    【解决方案1】:

    性能并不是真正的主要问题,至少对我来说不是。问题更多是关于代理键与自然键。

    国家/地区代码不是静态的。他们可以而且确实会改变。国家更改名称(例如埃塞俄比亚改为厄立特里亚)。它们产生(例如南斯拉夫或苏联的解体)并且它们不复存在(例如西德和东德)。当这种情况发生时,ISO 标准代码会发生变化。

    更多内容请关注Name Changes Since 1990: Countries, Cities, and More

    代理键往往更好,因为当这些事件发生时,键不会改变,只有引用表中的列会改变。

    出于这个原因,我更倾向于使用 int 主键创建国家和货币表。

    话虽如此,varchar 键字段会占用更多空间并具有某些性能劣势,除非您执行大量查询,否则这可能不会成为问题。

    为了完整起见,您可能需要参考Database Development Mistakes Made by AppDevelopers

    【讨论】:

    • 埃塞俄比亚改名了?!?
    • 该死的电话,让我在输入这个确切答案的过程中起床。说得好!
    • @SeanJA:根据那个链接,是的。这可能是暂时的变化。
    • 更重要的是,根据定义应该是唯一的东西,而不是(社会安全号码、护照号码等)
    • 阿比西尼亚成为埃塞俄比亚;厄立特里亚从埃塞俄比亚分离出来,现在是一个独立的国家。
    【解决方案2】:

    James Skidmore 的链接很重要。

    如果您将自己限制为国家和货币代码(分别为 2 和 3 个字符),您很可能无需声明 char(2) 和 char(3) 列。

    我想这不会是一个禁忌。如果您使用的是 8 位字符编码,那么您将分别查看大小为 smallint 或 mediumint 的列。

    【讨论】:

      【解决方案3】:

      我的回答是没有明确的答案。只需在您的项目中选择一种方法并保持一致。两者各有优缺点。

      @cletus 对使用生成的密钥提出了一个很好的观点,但是当您遇到数据相对静态的情况(例如国家/地区代码)时,为它们引入生成的密钥似乎过于复杂。尽管存在现实世界的政治,但对于大多数业务问题而言,国家代码的出现和消失并不是什么大问题(但如果您的数据积极涉及所有 190-210 个国家/地区,请遵循该建议)。

      普遍使用代理键是一种很好的流行策略。但请记住,它是对使用自然键对所有内容进行建模的数据库的响应。确认!打开一本 15 年前的数据库书。在任何地方使用自然键肯定会让您陷入困境,因为对问题域的初步理解证明是错误的。您确实希望在建模实践中保持一致性,但在明显不同的情况下使用不同的技术是可以的。

      我怀疑大多数现代数据库在 var(2) 外键上的性能将与 int 字段相同(或更好)。多年来,数据库一直支持文本外键。

      鉴于我们没有关于该项目的其他信息,如果您希望使用国家/地区代码作为外键,并且您可以选择这样做,我会说没关系。处理数据会更容易。这有点违反当前的做法,但是——在这种情况下——它不会让你陷入困境。

      【讨论】:

      • -1 这实际上是完全错误的。正如 James 在 forums.mysql.com/read.php?153,243809,243818#msg-243818 中指出的那样,MySQL(相关数据库)对 varchars 的处理与对 int 键的处理不同。
      • 我只是在猜测,由于数据库多年来一直这样做,它会被优化。这种假设不是第一次被证明是错误的!但是那篇文章是一个稍微不同的问题(“使用 VARCHAR(45) 是主键的好选择吗?”)这个问题是 CHAR(2) 在 200 行表(国家的数量)上的。不幸的是,该帖子一般没有讨论 FK 索引性能,以及 CHAR(2) 是否会比 VARCHAR(2) 更有效,我无法挖掘它。感谢您的链接。
      • 我同意,它讨论了拥有 45 字节 char 有多糟糕,因为它比普通 int 大 4-5 倍,但使用 char(2) 或 char(3) 大小不会有太大差异明智的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多