2011-10-31 57 views
2

我最近以GetHashCode()的方式指示了我,特别是“GetHashCode的使用者不能依赖它在一段时间内或跨应用程序域保持稳定”(From一个Eric Lippert blog article)。创建用于数据库的哈希码(即,不使用GetHashCode)

不幸的是,我一直在数据库中使用它来尝试加快查找速度(通过插入GetHashCode的结果而不是对文本字符串进行搜索)。我现在意识到这是一件非常糟糕的事情。

所以我仍然想知道我能做些什么。 有什么给定的字符串将被保证返回一个明显的抗碰撞整数,我可以用于查找?

我可以自己写一些东西,但我希望能够有内置的东西,我可以使用,而不必去加密库中的东西,感觉有点重量级。

+3

为什么你想这首先呢?让数据库做它的意义。 – SLaks

+0

@SLaks:这可能是我选择了一些关于数据库的老婆婆的故事,但我认为如果你想查找一个50个字符的字符串,它会比根据该字符串查找int更慢。考虑一下,你可能是正确的,如果我将列索引,它会做我想要的,然后一些。自从获得校验和或类似的结果以来,如果有答案,我仍然感兴趣,因为我认为这是一个非常有用的事情。 – Chris

+0

@Chris,“获取校验和或类似”通常不是很有用,对于某些特定情况非常有用。在每种情况下,你对校验和/哈希码都有不同的要求,所以你应该使用不同的算法。 – svick

回答

3

我鼓励你考虑其他人的看法:让数据库做它擅长的事情。为了优化查找而创建哈希代码表明表中的索引不是它们应该是的。

也就是说,如果你真的需要的哈希代码:如果你想有一个32位或64位的散列码

你不说。这将为一个字符串创建一个64位的哈希码。这是合理的碰撞抵抗。

public static long ComputeHashCode(string url) 
{ 
    const ulong p = 1099511628211; 

    ulong hash = 14695981039346656037; 

    for (int i = 0; i < url.Length; ++i) 
    { 
     hash = (hash^url[i]) * p; 
    } 

    // Wang64 bit mixer 
    hash = (~hash) + (hash << 21); 
    hash = hash^(hash >> 24); 
    hash = (hash + (hash << 3)) + (hash << 8); 
    hash = hash^(hash >> 14); 
    hash = (hash + (hash << 2)) + (hash << 4); 
    hash = hash^(hash >> 28); 
    hash = hash + (hash << 31); 

    if (hash == (ulong)UNKNOWN_RECORD_HASH) 
    { 
     ++hash; 
    } 
    return (long)hash; 
} 

注意,这是一个哈希代码和碰撞的可能性如果你有多达数十亿的记录是非常小的。经验法则:当项目数量超出散列码范围的平方根时,您有50%的碰撞机会。这个哈希码的范围是2^64,所以如果你有2^32个项目,你的碰撞几率约为50%。

请参阅http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=792http://en.wikipedia.org/wiki/Birthday_paradox#Probability_table了解更多信息。

+0

这是什么UNKNOWN_RECORD_HASH常量(我认为它是一个常量)? – Chris

+0

我把这个标记为正确的答案,因为你告诉我不要这么傻,并且回答了我的问题。 :) – Chris

+0

'UNKNOWN_RECORD_HASH'是我用来指示记录没有哈希码的值。我认为它与我的系统中的'0'相等,但您可以将其设置为任意常量值。该检查用于防止该方法生成未知记录哈希值。 –

1

正如SLaks在评论中指出的那样,查找数据是数据库擅长的。

如果您需要快速查找,请在该列上创建一个索引。至少,你不必再处理碰撞。

+0

我认为你是对的。现在我只需要去修复我所有可怕的代码。 ;-) – Chris