.NET:64位哈希码

3
我需要一个适用于字符串的64位哈希,而默认的.GetHashCode()仅返回32位int。我可以生成MD5/SHA1哈希,并仅使用前64位。但是因为这些算法具有加密安全性,它们对CPU的要求更高。
是否可以简单地在输入字符串的反向上调用第二次.GetHashCode()?并将两个32位int强制转换为64位long?它是否具有与'真正'的64位哈希(如CRC64)相同的扩展和碰撞抵抗性?

请查看以下答案了解实现64位哈希码的方法:http://stackoverflow.com/questions/7954602/creating-a-hashcode-for-use-in-a-database-ie-not-using-gethashcode/7960466#7960466。 - Jim Mischel
为什么这会被认为是“不构造性的”?想要一个你可以保证不变的哈希码有很好的理由。同时,想要一个64位哈希码也有很好的理由。 - Jim Mischel
你为什么认为需要一个64位的哈希函数? - Dour High Arch
@DourHighArch 因为32位会导致太多的冲突,而128位则过于浪费。 - Maestro
1
我绝对不建议使用哈希码作为记录键。正如Chris Haas在他的回答中指出的那样,哈希码并不能创建唯一的值。64位意味着发生冲突的可能性很小,但仍然会发生冲突。就像我在上面链接的回答中所说的,“让数据库做它擅长的事情吧”。使用哈希码来“优化”数据库访问几乎肯定是一个糟糕的决定。 - Jim Mischel
显示剩余2条评论
3个回答

3
你即将犯下一个很大的错误。64位哈希值远不足以保证唯一性,至少需要128位。guid是常见的选择。
生成唯一的32位或64位数字并不难,只需要使用下一个数字即可。关键在于你需要知道上一个数字。数据库引擎从记住内容的角度来看这不是问题。
使用自动增量列即可。

问题在于我需要快速查找字符串。如果我在SQLite中创建一个索引的TEXT列,那么所有字符串都会被存储两次(因为B-Tree索引),并且在一百万行后插入变得非常缓慢(因为B-Tree页面分裂等)。我同意您的观点,最好将PRIMARY KEY保持为普通的整数,但是使用第二个包含哈希的列并对其进行索引而不是TEXT列有什么问题吗? - Maestro
1
我不明白你为什么认为这会有所改进。Dbase引擎已经有很好的方法从字符串生成哈希值。你真的需要区分查找记录(简单快捷)和在拥有百万条记录的表中插入行的任务。这往往突出了SqlLite中的LITE。 - Hans Passant
1
这有点随意。采取措施以使自己相信。 - Hans Passant
我已经进行了许多基准测试。前一百万行的插入只需10秒钟,但额外的行(10,000行)需要30秒钟,这太慢了。这是由于SQLite的设计原因,需要先从磁盘读取现有索引的大部分内容,然后才能将新行添加到索引中。通过保持索引较小(使用哈希值),我想缩短那30秒钟。请参见http://stackoverflow.com/questions/8065949/net-key-value-database - Maestro
1
不,那只是告诉你它很慢。你已经知道了。你必须进行比较。测量一下当你添加额外的列并写入更多数据时是否更快。 - Hans Passant
显示剩余2条评论

2
只是为了让事情清楚,你知道 GetHashCode() 并不会生成任何唯一的东西,对吧?两个完全不同的字符串可能会返回相同的哈希码。该算法仅用于在哈希表中创建对象的均匀分布。

权威消息来源

GetHashCode 方法的默认实现不能保证对于不同的对象返回唯一的返回值。

此外,当你调用 GetHashCode() 时会发生什么的规则可能会随时间和跨应用程序域而改变。请参见这里中标题为“规则:GetHashCode 的使用者不能依赖其随时间或跨应用程序域保持稳定”的部分。

这在过去曾经困扰过人们。System.String.GetHashCode 的文档特别指出,在不同版本的CLR中,两个相同的字符串可能具有不同的哈希码,事实上它们确实如此。不要将字符串哈希值存储在数据库中,并期望它们永远相同,因为它们不会永远相同。
请点击这里查看某人的碰撞检测工作。

0

你选择64位有特别的原因吗?MD5更多用于检查内容是否意外改变,而SHA更多用于确保内容没有被故意更改。我肯定会至少使用SHA1。


1
因为它将作为SQLite数据库中的行ID,而这些ID最多只有64位。此外,我将要哈希的字符串平均长度为50字节,即使是8字节的哈希值也几乎是过度设计了。 - Maestro
50个字节是否存在安全问题?您是否会在哈希创建后检查字节是否已更改,或者安全地将哈希发送到远程位置以验证字节? - Erik Philips
不,没有那样的事情。这只是为了让SQLite可以索引较短的值。 - Maestro
我会使用Jim Mischel推荐的链接来达到你的目的。 - Erik Philips

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接