SQL - 最大 255 长度的唯一索引 - 哈希解决方案
SQL - max 255 length unique index - Hash Solution
我们 table 为用户存储令牌(即 accessTokens)。
问题是,有时标记的长度可能超过 255,MySQL/MariaDB 无法将其存储到在此列上具有唯一索引的 table 中。
我们需要唯一索引,因此一种解决方案是添加额外的列,其中包含最大长度为 255 的令牌散列,并将唯一索引放入其中。任何 search/save 都将通过此哈希,匹配后,我们 select 整个令牌并将其发回。经过大量思考和谷歌搜索,这可能是该用例唯一可行的解决方案(但您可以尝试给我们另一个解决方案)。
我们现在生成的每个令牌至少是部分随机的,因此哈希冲突的可能性很小"ok",用户不会永远卡在下一个请求中,它应该通过。
你知道2017年有什么好的现代方法吗?有一些关于此方法的散列冲突的统计数据将不胜感激。
哈希仅供内部使用 - 我们不需要它是安全的(快速不安全的哈希最适合我们),它应该足够长以减少冲突的可能性,但绝不能超过 255 的长度限制.
PS:设置允许更多长度的特殊版本 database/table 是不可行的,我们在一些没有迁移的旧系统中也需要它。
这些访问令牌可以用 8 位字符表示吗?即里面的字符都是从ASCII还是iso-8859-1字符集中取的?
如果是这样,您可以通过使用 COLLATE latin1_bin
声明访问令牌列来获得比 255 更长的唯一索引。索引前缀的限制是 767 字节,但 VARCHAR 列中的 utf8 字符每个字符占用 3 个字节。
因此,具有 767 个唯一 latin1 字符的列应该是唯一可索引的。如果您的唯一哈希值都适合大约 750 个字节,那么这可能会解决您的问题。
如果不是...
您已经为您的长令牌请求了一个具有 "low" 冲突风险的哈希函数。 SHA1 is pretty good, and is available as a function in MySQL. SHA512 甚至更好,但并不适用于所有 MySQL 服务器。但问题是:将长令牌的前 250 个字符或最后 250 个字符用作散列的冲突风险是多少?
我为什么要问?因为您的规范要求在对 MySQL 唯一索引来说太长的列上使用唯一索引。您打算通过使用散列函数来解决该问题,该散列函数也不 保证 是唯一的。这给了你两种选择,这两种选择都要求你以很小的碰撞概率生活。
- 添加一个由
SHA2('token', 512)
计算的 hash
列,并接受极小的碰撞概率。
- 添加一个由
LEFT('token', 255)
计算的 hash
列,并接受极小的碰撞概率。
您可以简单地通过删除令牌列上索引的唯一约束来实现第二个选择。 (换句话说,做的很少。)
SHA 具有众所周知的碰撞特性。要评估其他一些哈希函数,需要知道您的长令牌的冲突特征,而您没有告诉我们这些。
对 HASHing 的评论
UNHEX(MD5(token))
适合 16 个字节 - BINARY(16)
.
至于冲突:理论上,在 9 万亿行的 table 中发生冲突的几率只有 9 万亿分之一。
对于 BINARY(20)
中的 SHA()
,赔率甚至更低。在我看来,更大的 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以后的版本大概可以执行'reconfigure'.
类似问题:
我们 table 为用户存储令牌(即 accessTokens)。
问题是,有时标记的长度可能超过 255,MySQL/MariaDB 无法将其存储到在此列上具有唯一索引的 table 中。
我们需要唯一索引,因此一种解决方案是添加额外的列,其中包含最大长度为 255 的令牌散列,并将唯一索引放入其中。任何 search/save 都将通过此哈希,匹配后,我们 select 整个令牌并将其发回。经过大量思考和谷歌搜索,这可能是该用例唯一可行的解决方案(但您可以尝试给我们另一个解决方案)。
我们现在生成的每个令牌至少是部分随机的,因此哈希冲突的可能性很小"ok",用户不会永远卡在下一个请求中,它应该通过。
你知道2017年有什么好的现代方法吗?有一些关于此方法的散列冲突的统计数据将不胜感激。
哈希仅供内部使用 - 我们不需要它是安全的(快速不安全的哈希最适合我们),它应该足够长以减少冲突的可能性,但绝不能超过 255 的长度限制.
PS:设置允许更多长度的特殊版本 database/table 是不可行的,我们在一些没有迁移的旧系统中也需要它。
这些访问令牌可以用 8 位字符表示吗?即里面的字符都是从ASCII还是iso-8859-1字符集中取的?
如果是这样,您可以通过使用 COLLATE latin1_bin
声明访问令牌列来获得比 255 更长的唯一索引。索引前缀的限制是 767 字节,但 VARCHAR 列中的 utf8 字符每个字符占用 3 个字节。
因此,具有 767 个唯一 latin1 字符的列应该是唯一可索引的。如果您的唯一哈希值都适合大约 750 个字节,那么这可能会解决您的问题。
如果不是...
您已经为您的长令牌请求了一个具有 "low" 冲突风险的哈希函数。 SHA1 is pretty good, and is available as a function in MySQL. SHA512 甚至更好,但并不适用于所有 MySQL 服务器。但问题是:将长令牌的前 250 个字符或最后 250 个字符用作散列的冲突风险是多少?
我为什么要问?因为您的规范要求在对 MySQL 唯一索引来说太长的列上使用唯一索引。您打算通过使用散列函数来解决该问题,该散列函数也不 保证 是唯一的。这给了你两种选择,这两种选择都要求你以很小的碰撞概率生活。
- 添加一个由
SHA2('token', 512)
计算的hash
列,并接受极小的碰撞概率。 - 添加一个由
LEFT('token', 255)
计算的hash
列,并接受极小的碰撞概率。
您可以简单地通过删除令牌列上索引的唯一约束来实现第二个选择。 (换句话说,做的很少。)
SHA 具有众所周知的碰撞特性。要评估其他一些哈希函数,需要知道您的长令牌的冲突特征,而您没有告诉我们这些。
对 HASHing 的评论
UNHEX(MD5(token))
适合 16 个字节 - BINARY(16)
.
至于冲突:理论上,在 9 万亿行的 table 中发生冲突的几率只有 9 万亿分之一。
对于 BINARY(20)
中的 SHA()
,赔率甚至更低。在我看来,更大的 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以后的版本大概可以执行'reconfigure'.
类似问题: