在MySQL中使用INT和VARCHAR作为主键之间有可测量的性能差异吗?我想使用VARCHAR作为参考列表的主键(认为美国州,国家代码)和同事不会在INT AUTO_INCREMENT作为所有表的主键上让步。

我的论点是,INT和VARCHAR之间的性能差异可以忽略不计,因为每个INT外键引用都需要一个JOIN来理解引用,VARCHAR键将直接显示信息。

那么,有人对这个特殊的用例以及与之相关的性能问题有过经验吗?


当前回答

这与性能无关。这是关于什么是一个好的主键。独一无二且随时间不变。您可能认为国家代码之类的实体永远不会随着时间而改变,并且是主键的良好候选者。但痛苦的经验是,这种情况很少发生。

INT AUTO_INCREMENT满足“唯一且随时间不变”的条件。因此才会有偏好。

其他回答

这个问题是关于MySQL的,所以我说有很大的区别。如果是关于Oracle(它将数字存储为字符串——是的,一开始我不敢相信),那么没有太大区别。

表中的存储不是问题,更新和引用索引才是问题。涉及基于主键查找记录的查询非常频繁——您希望它们尽可能快地出现,因为它们经常发生。

问题是CPU自然地处理4字节和8字节的整数,在硅中。它比较两个整数真的很快——它发生在一个或两个时钟周期内。

现在看一个字符串——它由很多字符组成(现在每个字符超过一个字节)。比较两个字符串的优先级不能在一个或两个循环中完成。相反,字符串的字符必须迭代,直到发现差异。我确信在某些数据库中有一些技巧可以让它更快,但在这里这无关紧要,因为在硅中,CPU会自然地进行int比较,并且速度很快。

我的一般规则-每个主键都应该是一个自动递增的INT,特别是在使用ORM (Hibernate, Datanucleus,等等)的OO应用程序中,对象之间有很多关系-它们通常总是作为一个简单的FK实现,DB快速解析这些关系的能力对你的应用程序很重要。 响应性。

和往常一样,没有统一的答案。“这取决于!我不是在开玩笑。我对原始问题的理解是小表上的键-像Country(整数id或char/varchar代码)是潜在的大表(如地址/联系表)的外键。

当您希望从DB返回数据时,这里有两种场景。首先是一个列表/搜索类型的查询,其中您希望列出所有带有州和国家代码或名称的联系人(id没有帮助,因此需要查找)。另一个是在主键上的get场景,它显示单个联系人记录,其中需要显示州名和国家。

For the latter get, it probably does not matter what the FK is based on since we are bringing together tables for a single record or a few records and on key reads. The former (search or list) scenario may be impacted by our choice. Since it is required to show country (at least a recognizable code and perhaps even the search itself includes a country code), not having to join another table through a surrogate key can potentially (I am just being cautious here because I have not actually tested this, but seems highly probable) improve performance; notwithstanding the fact that it certainly helps with the search.

由于代码很小——国家和州通常不超过3个字符,在这种情况下使用自然键作为外键是可以的。

另一种情况是,键依赖于较长的varchar值,也可能依赖于较大的表;代理键可能具有优势。

至于主键(Primary Key),任何物理上使行唯一的元素都应该被确定为主键。

对于作为外键的引用,使用自动递增的整数作为代理是一个好主意,主要有两个原因。 -首先,通常在连接中产生的开销更少。 -其次,如果你需要更新包含唯一varchar的表,那么更新必须级联到所有的子表,并更新所有的子表以及索引,而使用int代理,它只需要更新主表及其索引。

使用代理的缺点是,你可能会允许更改代理的含义:

ex.
id value
1 A
2 B
3 C

Update 3 to D
id value
1 A
2 B
3 D

Update 2 to C
id value
1 A
2 C
3 D

Update 3 to B
id value
1 A
2 C
3 B

这完全取决于您在结构中真正需要担心的是什么,以及什么最重要。

请允许我说,考虑到性能范围(开箱即用定义),肯定有区别:

1-在应用程序中使用代理int更快,因为你不需要在你的代码或查询中使用ToUpper(), ToLower(), ToUpperInvarient()或ToLowerInvarient(),这4个函数有不同的性能基准。请参阅关于此的Microsoft性能规则。(申请的表现)

2-使用代理int保证不随时间改变键。甚至国家代码也可能发生变化,请参阅维基百科ISO代码如何随时间变化。这将花费大量时间来更改子树的主键。(数据维护的表现)

3- ORM解决方案似乎有问题,比如当PK/FK不是int时NHibernate。开发人员(性能)

您提出了一个很好的观点,即可以通过使用所谓的自然键而不是代理键来避免一些连接查询。只有您才能评估这样做的好处在您的应用程序中是否显著。

也就是说,您可以测量应用程序中对快速最重要的查询,因为它们处理大量数据或执行非常频繁。如果这些查询可以从消除连接中获益,并且不会因使用varchar主键而遭受损失,那么就这样做。

不要对数据库中的所有表使用这两种策略。在某些情况下,天然键可能更好,但在其他情况下,替代键可能更好。

另一些人提出了一个很好的观点,即在实践中,自然键很少永远不会更改或有重复,因此代理键通常是值得的。