使用 char 作为主键/外键是否不行?

问题描述 投票:0回答:4

考虑有一堆链接到“国家”或“货币”表的表。

为了使数据更易于阅读,我想在这两个表中的每个表中使用国家代码(例如美国、GB、AU)和货币代码(美元、澳元)创建 CHAR 字段,并且所有其他表将使用此 CHAR作为外键。

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

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

sql mysql database-design data-modeling innodb
4个回答
21
投票

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

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

更多内容参见 自 1990 年以来的名称变更:国家、城市等

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

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

话虽这么说,varchar 键字段将使用更多空间并具有某些性能缺点,除非您执行大量查询,否则这些缺点可能不会成为问题。

为了完整起见,您可能需要参考应用程序开发人员犯的数据库开发错误


1
投票

James Skidmore 的链接很重要,值得阅读。

如果您将自己限制为国家/地区和货币代码(分别为 2 个和 3 个字符),那么您很可能可以不必声明列 char(2) 和 char(3)。

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


0
投票

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

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

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

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

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


0
投票

我想说相反。我知道这是一个老问题,但我在决定是否使用更激进的自然键时遇到了它。

就您而言,自然键优于代理键。它的性能肯定更好:CHAR(2) 就像 SMALLINT,2 个字节;但是,您可以避免仅仅为了查找此内容而进行的许多不必要的联接。总的来说,您的应用程序的性能会更好/至少不会更差。

即使存在性能损失,自然键(例如护照号码)对我来说也是首选。我不同意主键不能随时间变化的想法,但您应该避免使用经常变化的自然键。在 PK 更新的罕见情况(例如护照号码)中,您始终可以使用级联更新。

我认为使用合成PK也是一个很好的做法。

© www.soinside.com 2019 - 2024. All rights reserved.