SQL - 最大255长度唯一索引 - 哈希解决方案

时间:2017-05-29 11:44:38

标签: mysql indexing hash token mariadb

我们有用于为用户存储令牌的表(即accessTokens)。

问题是,有时令牌的长度可能超过255,而MySQL / MariaDB无法将其存储到此列中具有唯一索引的表中。

我们需要唯一索引,因此一种解决方案是添加具有最大长度为255的令牌哈希的附加列,并为其添加唯一索引。任何搜索/保存都将通过此哈希,匹配后,我们选择整个令牌并将其发回。经过大量的思考和谷歌搜索后,这可能是这个用例唯一可行的解​​决方案(但你可以尝试给我们另一个)。

我们现在生成的每个令牌至少部分是随机的,因此哈希冲突的可能性稍微“好”,用户不会永远停留在下一个请求中,它应该通过。

你知道2017年有什么好的现代方法吗?有一些关于这种方法的哈希冲突的统计数据将不胜感激。

哈希仅供内部使用 - 我们不需要它是安全的(快速不安全的哈希对我们来说是最好的),它应该足够长,以便具有较低的冲突机会,但绝不能超过255个长度限制。 / p>

PS:设置允许更长的数据库/表格的特殊版本是不可行的,我们也需要它在一些较旧的系统中而不需要迁移。

2 个答案:

答案 0 :(得分:1)

这些访问令牌是否可以用8位字符表示?也就是说,它们中的所有字符都取自ASCII或iso-8859-1字符集?

如果是这样,通过使用COLLATE latin1_bin声明访问令牌列,您可以获得比255更长的唯一索引。索引前缀的限制是767 bytes ,但VARCHAR列中的utf8字符每个字符占用3个字节。

因此,具有767个唯一latin1字符的列应该是唯一可索引的。如果您的唯一哈希值大约适合750个字节,那么这可以解决您的问题。

如果没有......

您已经要求具有“低”碰撞风险的长令牌的哈希函数。 SHA1 is pretty good,可在MySQL中作为函数使用。 SHA512甚至更好,但并不适用于所有MySQL服务器。但问题是:获取长令牌的第一个或最后250个字符并将它们用作哈希值的碰撞风险是多少?

我为什么这么问?因为您的规范要求列上的唯一索引对于MySQL唯一索引而言太长。您建议通过使用也不是保证的哈希函数来解决该问题。这给你两个选择,这两个选择都要求你以较小的碰撞概率生活。

  1. 添加hash列,该列由SHA2('token', 512)计算,并且具有微小的碰撞概率。
  2. 添加hash列,该列由LEFT('token', 255)计算,并以极小的碰撞概率生效。
  3. 您只需删除令牌列上索引的唯一约束即可实现第二个选择。 (换句话说,做得很少。)

    SHA系列具有众所周知的碰撞特性。要评估其他一些哈希函数,需要知道你的长令牌的碰撞特征,而你还没有告诉我们那些。

答案 1 :(得分:0)

关于HASHing的评论

UNHEX(MD5(token))符合16个字节 - BINARY(16)

至于碰撞:从理论上讲,9万亿只中只有一次机会在一个9万亿行的表格中发生碰撞。

对于SHA()中的BINARY(20),赔率甚至更低。在我看来,更大的shas是矫枉过正的。

超越767限制至3072

⚈升级到5.7.7(MariaDB 10.2.2?),限制为3072字节 - 但您的云可能无法提供此功能;
   ⚈重新配置(如果保留5.6.3 - 5.7.6(MariaDB 10.1?)) - 要改变的4件事:Barracuda + innodb_file_per_table + innodb_large_prefix +动态或压缩。

5.5的后续版本可能会执行'重新配置'。

类似问题:Does MariaDB allow 255 character unique indexes?