为什么通常认为使用字符串键是一个坏主意?


24

这一直困扰着我一段时间。大多数时候,在将数据存储在诸如哈希表之类的结构中时,程序员,书籍和文章都坚持认为用String值对所述结构中的元素进行索引是不正确的做法。然而,到目前为止,我还没有找到一个单一的资料来源来解释为什么这被认为是不好的作法。是否取决于编程语言?在底层框架上?在执行上?

举两个简单的例子,如果有帮助的话:

类似于SQL的表,其中的行由String主键索引。

.NET字典,其中的键是字符串。


9
通常,拥有字符串键不是一个坏主意。我怀疑这些声明是在可以使用更好的密钥类型的环境中进行的。我一直都有带字符串键的.net字典。您能举一些这种说法的例子吗?
CodesInChaos

3
通常,您希望主键在对象/行的整个生命周期内保持不变。因此,例如,username作为users表的主键可能不是最好的主意,并且您希望使用自动递增的ID。但这username只是一个字符串,只是可变属性是主要问题
CodesInChaos

在数据库中,考虑如何索引字符串而不是整数。

@CodesInChaos我希望我能记得我在大多数情况下找到的地方,但是现在我可以粘贴使我想起这个问题的位。它来自Valve的GDC幻灯片演示,其中讨论了游戏对话并以<key = string,value = object>对的形式存储了有关世界的事实。

2
字符串很好。只是不是“魔术”弦。因此,在使用哈希表时,请确保代码中没有裸字符串。您应该避免使用大文本值作为键,因为它们不能很好地发挥作用,但是在大多数实际情况下,短文本字符串的速度与整数一样快(它们不是大型数据库)。您还可以使用备用键,例如,主键是数字,但也有一个“子段”或唯一字符串,该字符串也是唯一的。
ipaul

Answers:


17

这基本上与两件事有关:

1)查找的速度(例如整数值要好得多)

2)索引的大小(字符串索引会爆炸)

现在,这一切都取决于您的需求和数据集的大小。如果表或集合中有10-20个元素,则键的类型无关紧要。即使使用字符串键,它也会非常快。

PS可能与您的问题无关,但Guid也被认为对数据库密钥不利(16字节Guid与4字节整数)。对于大数据量,Guids会减慢查找速度。


并非总是如此-可以使用增量GUID。索引仍然会更大,但是查找代价将不会那么差。
2013年

7
其实他们很好。您必须查看时间磁盘IO时间与比较内存中的值之间的关系。由于磁盘访问时间使内存比较不堪重负,因此分析数据库性能中唯一真正重要的是IO。密钥是GUID,字符串还是整数并不重要。索引大小会影响一个页面中可以容纳多少索引值,但是密钥是4字节int(可能不够大且不能由客户端生成)还是16字节值并不重要。在某些数据库中,rowId的大小可以为16个字节。
ipaul

9

使用字符串作为键,或者更准确地说,使用字符串文字作为键,而又没有纯粹的性能/效率原因,这又是一个问题。错别字。如果您将字符串文字用作字典中的键,则当您"ReceiverId"变成时,您会感到非常讨厌"RecieverId"。设置常量以存储键值,并在每次访问字典时重用它们。

可以说,这是琐碎的和显而易见的,但是在Web上大量的.NET代码示例使用字符串文字,传播了这种可疑的做法。在代码库中散布着所有Sessions,ViewStates和QueryParams的ASP.NET在这里特别内gui。


不琐事恕我直言。我也看到哪里有钥匙的情况下"1",并"1 "在同一个表。
pswg 2013年

当您还需要区分大小写时,Get会变得更加有趣。看到包括我在内的许多人直接跌入那个人。
Tony Hopkinson

至少在C#中,比使用常量更好的是使用表达式。这样,您可以从方法/属性等的名称中生成字符串,以便您的字符串查找变得安全且重构友好。
GoatInTheMachine'5

4

这里有很多折衷。实际上,我经常使用字符串键,但是经常包括用于连接的代理辅助键(显然,如果使用MySQL,那将是另一种方法)。在某些情况下我却不这样做。

首先,我喜欢将自然键声明为数据库可以很好处理的主键(例如PostgreSQL)。这有助于规范化,并使数据库设计更加清晰。代理键使加入变得更容易。

我通常添加代理键有两个原因:

  1. 并不总是清楚什么是自然键。有时这些必须更改。当将自然的复合键用于联接和参照完整性时,更改十分复杂且容易出错。

  2. 复合键上的联接性能存在问题,一旦您走了自然键路线,就会陷入困境。

但是,在自然键为定义键,单列和文本键的情况下,我通常会加入字符串键。我这样做的原因是,这通常避免在查找时加入联接。最常见的用法是围绕枚举类型的用例提供适当的数据库设计。在大多数情况下,这些并没有要求额外加入日常查询。因此,在这种情况下,将字符串键作为连接键很有意义。

例如,在LedgerSMB中,我们存储帐户分类。这些通过字符串引用来标识。一些其他数据与字符串引用一起存储,该字符串引用用于实施有关可能影响帐户的分类组合的规则。唯一需要逻辑的时间是保存一组分类时,因此我们加入字符串键。

至于为什么默认值是整数键,我不认为这只是索引大小的问题。一个大问题是密钥管理。由于密钥是任意的,并且您可能要处理数百万条记录,因此必须有一种生成唯一字符串的方法。在某些情况下,人们为此使用UUID,但是UUID冲突的可能性不为零,并且在存储数十亿条记录的情况下,当增量整数类型发生冲突的可能性为零时,这种机会实际上可能会变得足够高根据定义。


如果您设法使整数类型回绕为零,则它不是非零。对于无符号的32位类型,它只有4G的距离,令人不安地接近“数十亿条记录”……
Donal Fellows

如果您有一个可以告诉“错误而不是环绕”的数据库,则该数据库为零。无论如何,与增加伪随机值相比,使用递增的整数管理冲突的可能性要容易得多。
克里斯·特拉弗斯

1

使用字符串作为键存在许多潜在的问题,尤其是在涉及类似sql的表时。如@bunny所述,表的索引将更大,但我认为更重要的是,与表的任何外键关系都将使两个表都包含字符串,而不是轻量(整数)标识符。如果您发现还有更多引用第一个表的表,则字符串键将在整个数据库中扩散。


1

它本身并不是一个坏主意,通常事后认为20/20是一个糟糕的设计折衷方案。字符串的灵活性和范围以及额外的成本和复杂性。

如果整数明智地完成了工作范围,而大量昂贵的处理不需要知道整数代表什么,则使用1。


0

您以某种方式从哈希表中检索了错误的数据。

您是说“ DaytimeTelephone”还是“ EveningTelephone”?

要么

您是说1234567还是1234576?

虽然数字对于机器而言可以说效率更高,但只要出现问题(确实如此),它就由您和我这样的人来了解发生了什么,并在那时节省了一些字节的存储空间和几个微(纳米) -处理的秒失去出清晰度每一次。


1
因此,您最终得到了一个常量列表,使用代码中的常量名称来表示幻数... Java进行了枚举,将其进一步抽象化,只剩下名称和顺序号映射不可见。
jwenting

-1

很多折衷选择,没有一个正确的答案。许多程序员永远不会考虑在数据库中使用字符串键,因为他们不了解哈希和数据库的工作方式。在很多情况下,只要字符串键非常稳定或无意义(替代),它们都是不错的设计选择。


2
该答案不会添加其他答案中尚未提及的任何内容,后者会更好。
Martijn Pieters 2014年

-2

当涉及到具有约10-100条短字符串记录的查找表时,字符串键才有意义。相关数据更具可读性+例如更改跟踪(数字/引导ID与字符串,例如“管理员”);顺便说一句,ASP.NET Membership数据库使用AspNetRoles的字符串键。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.