二进制和后退的SQL字符串文字十六进制密钥

时间:2018-01-12 13:25:06

标签: mysql sql binary hex checksum

经过广泛搜索后,我依靠堆栈溢出的智慧来帮助我。 问题: 我有一个数据库表,应该有效地存储格式(UserKey, data0, data1, ..)的值,其中UserKey将作为主键处理,但至少作为索引。 UserKey本身(外部定义)是一个32个字符的字符串,表示校验和,它恰好是(一个非常大的)十六进制数,即它看起来像UserKey = "000000003abc4f6e000000003abc4f6e"

现在我当然可以将这个UserKey存储在char(32)-field中,但我觉得这样效率很低,因为我存储了一系列原则上的任意字符,即为每个字符保留空间以获得更多信息。我需要存储十六进制字符(0..9,AF)。

所以我的想法是将这个字符串文字转换为它真正代表的十六进制数字,然后存储它。但是这个数字(32 * 4位= 16Bytes)太大而无法存储/处理,因为SQL只能处理8Bytes的BIGINTS。

我的第二个想法是将其转换为BINARY(16)表示,这应该是紧凑且有效的内存。但是,我不知道如何有效地在这两种格式之间进行转换,因为SQL内部只处理最多8字节的数字。

也许有一种方法可以将这个字符串逐块转换为二进制并以某种方式将二进制拼接在一起,方式如下:

 UserKey == concat( stringblock1, stringblock2, ..)
 UserKey_binary = concat( toBinary( stringblock1 ), toBinary( stringblock2 ), ..)

所以我的问题是:SQL中是否有任何可以解决此问题的机制?自定义解决方案将如何? (我发现很难相信我应该是第一个遇到这样一个问题的人,因为在许多应用程序中使用可笑的长hashkeys变得相当现代)

此外,Userkey_binary应该作为表的关系键,所以我希望通过这种更紧凑的表示获得一点速度,因为它需要确定最小位数的差异。另外,我想提一下,如果可能的话,我希望在服务器端进行任何转换,以便不必更改用户脚本(如果可能,用户端仍应传输字符串文字而不是[部分] ]插入语句中转换的值)

1 个答案:

答案 0 :(得分:0)

在对我之前的陈述的矛盾中,似乎MySQL的#!函数逐块地执行字符串转换,然后像我上面说的那样进行连接,因此该方法也适用于更大的HEX文字值比BIGINT的8字节限制。这里有一个示例表,说明了这一点:

UNHEX()

主键是一个生成的列,因此对charcol的更新是与来自外部的字符串文字与表交互的指定方式:

CREATE TABLE `testdb`.`tab` (
`hexcol_binary` BINARY(16) GENERATED ALWAYS AS (UNHEX(charcol)) STORED,
`charcol` CHAR(32) NOT NULL,
PRIMARY KEY (`hexcol_binary`));

看到hexcol_binary上的构建键和索引按预期工作。

要验证加速,请执行

REPLACE into tab (charcol) VALUES ('1010202030304040A0A0B0B0C0C0D0D0');
SELECT HEX(hexcol_binary) as HEXstring, tab.* FROM tab;

在hexcol_binary列上的查找效果要好得多,特别是如果它的附加值是唯一的。

注意:十六进制转换不关心十六进制字符A到F是否为转换过程大写,但是charcol对此非常敏感。