我有一个TCG卡数据库,我正在尝试确定一个主键。我最初用代理键定居,但我意识到有时候,我忘记添加卡片,例如促销卡片。使用代理键会产生问题,因为它们会以最新的自动增量添加到数据库中,并且我不希望它们的ID依赖于它们的插入顺序。我想也许我可以对某些卡功能进行哈希处理并将其用作主键?
以下面的伪代码为例:
// set code, date released, collector number, name
$crc = crc32(implode(',', ['A', '1993-08-03', '232a', 'black lotus']));
echo $crc; // 4199975187
现在可能的卡数量大约在25k左右,每6个月增加100-300个左右。
我知道我可以通过将其转换为base 62
来缩短哈希值,但我会将这些哈希值加入到用户手中。库存表因此我认为在int
维护这些将是最好的选择。
答案 0 :(得分:2)
我对此不以为然:
这对代理键有问题,因为它们会以最新的自动增量添加到数据库中,我不希望它们的ID依赖于它们的插入顺序。
ID(正确:“Id”,因为它是缩写,而不是初始主义)是“Identity”的缩写,“Identity”具有每个元素唯一的单一属性,也就是说,它用于标识每个元素。你不应该附加任何其他内涵,因此它随插入顺序单调增加的事实是无关紧要的,并且生成的标识列对数据排序是没有意义的(除非它在用于Id-lookup的索引中)。在这种情况下,您应该将Ids视为不透明的句柄。
当然,如果你使用摘要(例如CRC-32),Ids的排序顺序是没有意义的,但实际上比单调增加Id的效用要小。
您正确识别了哈希冲突的风险,CRC-32的范围空间仅为32位,如果您有25,000张卡,那么生日问题会告诉我们在如此小范围的空间中发生哈希冲突的可能性并非无足轻重。
只需使用自动生成的Id值即可。 :)
使用计算的哈希作为标识符/键确实具有实用性 - 这就是哈希表的工作方式,因为它允许您按值快速查找某些内容,而无需实际搜索所有表(例如,查找黑色莲花)卡,像你一样获取其属性的哈希值,然后在ID列中查找计算的哈希,而不必执行SELECT ... WHERE code = 'A' AND ... AND name = 'black lotus'
,但它确实要求您首先知道每个属性值,如果您设置了右表索引这很快变得没有实际意义。
使用哈希作为主键的主要问题是:
QED:)
答案 1 :(得分:-1)
研究此链接: - http://preshing.com/20110504/hash-collision-probabilities/
对于任何 32位散列和25K +值,碰撞的几率几乎为1/10 - 无论散列算法有多好。
您需要一种处理冲突的机制或切换到64位哈希算法。根据这个,CRC64似乎已经足够好了 crc collisions at various bit sizes 1820万个样本没有碰撞。