以二进制形式插入和选择 UUID(16)
Inserting and selecting UUIDs as binary(16)
我不明白为什么
SELECT UUID();
Returns 类似于:
3f06af63-a93c-11e4-9797-00505690773f
但是如果我将它插入一个二进制 (16) 字段(UUID() 函数),例如一个 BEFORE INSERT 触发器和 运行 一个 select,它 returns类似于:
0782ef48-a439-11
注意这两个UUID不是同一个数据
我意识到二进制和 UUID 字符串看起来不一样,但是 selected 数据不应该至少一样长吗?否则它怎么可能是唯一的?
存成char(36)是不是更好?我只需要它是唯一的以防止重复插入。它从不 select 编辑或用于联接。
编辑:
之前触发器会是这样的:
BEGIN
if NEW.UUID IS NULL THEN
NEW.UUID = UUID();
END IF
END
因此,作为对评论的回应。将 36 字符 UUID 存储为 binary(16) 的正确方法是以如下方式执行插入:
INSERT INTO sometable (UUID) VALUES
(UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")))
UNHEX
因为 UUID 已经是一个十六进制值。我们 trim (REPLACE
) 语句中的破折号将长度减少到 32 个字符(我们的 16 个字节表示为 HEX
)。显然,您可以在存储它之前的任何时候执行此操作,因此它不必由数据库处理。
您可以像这样检索 UUID:
SELECT HEX(UUID) FROM sometable;
以防万一有人遇到这个话题并且不确定它是如何工作的。
请记住:如果您使用 UUID 选择行,在条件 :
上使用 UNHEX()
SELECT * FROM sometable WHERE UUID = UNHEX('3f06af63a93c11e4979700505690773f');
或 literal notation(如 Alexis Wilke 所述):
SELECT * FROM sometable WHERE UUID = 0x3f06af63a93c11e4979700505690773f;
而不是HEX()
列:
SELECT * FROM sometable WHERE HEX(UUID) = '3f06af63a93c11e4979700505690773f';
最后一个解决方案虽然可行,但需要 MySQL HEX
读取所有 UUID,然后才能确定哪些行匹配。效率很低。
编辑:如果您使用的是 MySQL 8,您应该查看 SlyDave 的回答中提到的 UUID 函数。这个答案仍然是正确的,但它没有优化可以使用这些函数本机完成的 UUID 索引。如果你在 < MySQL 8 上,你可以实现 Devon 的 polyfill,它提供与 MySQL.
以前版本相同的功能
从 MySQL 8 开始,您可以使用两个新的 UUID functions:
BIN_TO_UUID
SELECT BIN_TO_UUID(uuid, true) AS uuid FROM foo;
-- 3f06af63-a93c-11e4-9797-00505690773f
UUID_TO_BIN
INSERT INTO foo (uuid) VALUES (UUID_TO_BIN('3f06af63-a93c-11e4-9797-00505690773f', true));
此方法还支持重新排列 uuid 的时间部分以增强索引性能(通过按时间顺序排列),只需将第二个参数设置为 true - 这仅适用于 UUID1。
如果您在 UUID_TO_BIN
标志上使用 true
来提高索引性能(推荐),您还必须在 BIN_TO_UUID
上设置它,否则它无法正确转换回来。
有关详细信息,请参阅文档。
我正在使用 MariaDB,所以 BIN_TO_UUID
函数系列不存在。无论如何,我设法得到了相应的值。
bin -> hex
这里,uuid
是一个uuid的binary(16)值;您将使用下面的值来 SELECT 它的可读版本。
LOWER(CONCAT(
SUBSTR(HEX(uuid), 1, 8), '-',
SUBSTR(HEX(uuid), 9, 4), '-',
SUBSTR(HEX(uuid), 13, 4), '-',
SUBSTR(HEX(uuid), 17, 4), '-',
SUBSTR(HEX(uuid), 21)
))
hex -> bin
此处,cc6e6d97-5501-11e7-b2cb-ceedca613421
是 UUID 的可读版本,您将在 WHERE 子句中使用下面的值来查找它。
UNHEX(REPLACE('cc6e6d97-5501-11e7-b2cb-ceedca613421', '-', ''))
干杯
其他答案正确。 UUID()
函数 returns 一个 36 个字符的字符串,需要使用显示的函数(UNHEX()
或在较新的平台上,UUID_TO_BIN()
)进行转换。
但是,如果您使用自己的软件创建 UUID,则可以改用 Hexadecimal Literal notation。
所以我会在 MySQL UUID()
函数中使用以下内容:
INSERT INTO sometable (id) VALUES (UNHEX(REPLACE(UUID(), '-', ''))); -- all versions
INSERT INTO sometable (id) VALUES (UUID_TO_BIN(UUID()); -- since v8.0
但如果我生成自己的 UUID,请使用它;
INSERT INTO sometable (id) VALUES 0x3f06af63a93c11e4979700505690773f;
同样,您可以在 WHERE
子句中使用十六进制文字:
SELECT * FROM sometable WHERE id = 0x3f06af63a93c11e4979700505690773f;
如果您不必每次都将数据转换为 UUID 字符串,这样会更快。
注意:'0xaBc
中的'x'
区分大小写。然而,十六进制数字不是。
BIN_TO_UUID 的 Polyfill 和 MySQL 的 UUID_TO_BIN 5 以及 swap_flag 参数。
DELIMITER $$
CREATE FUNCTION BIN_TO_UUID(b BINARY(16), f BOOLEAN)
RETURNS CHAR(36)
DETERMINISTIC
BEGIN
DECLARE hexStr CHAR(32);
SET hexStr = HEX(b);
RETURN LOWER(CONCAT(
IF(f,SUBSTR(hexStr, 9, 8),SUBSTR(hexStr, 1, 8)), '-',
IF(f,SUBSTR(hexStr, 5, 4),SUBSTR(hexStr, 9, 4)), '-',
IF(f,SUBSTR(hexStr, 1, 4),SUBSTR(hexStr, 13, 4)), '-',
SUBSTR(hexStr, 17, 4), '-',
SUBSTR(hexStr, 21)
));
END$$
CREATE FUNCTION UUID_TO_BIN(uuid CHAR(36), f BOOLEAN)
RETURNS BINARY(16)
DETERMINISTIC
BEGIN
RETURN UNHEX(CONCAT(
IF(f,SUBSTRING(uuid, 15, 4),SUBSTRING(uuid, 1, 8)),
SUBSTRING(uuid, 10, 4),
IF(f,SUBSTRING(uuid, 1, 8),SUBSTRING(uuid, 15, 4)),
SUBSTRING(uuid, 20, 4),
SUBSTRING(uuid, 25))
);
END$$
DELIMITER ;
--
-- Tests to demonstrate that it works correctly. These are the values taken from
-- https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid-to-bin
--
-- If you run these SELECTs using the above functions, the
-- output of the two columns should be exactly identical in all four cases.
SET @uuid = '6ccd780c-baba-1026-9564-5b8c656024db';
SELECT HEX(UUID_TO_BIN(@uuid, 0)), '6CCD780CBABA102695645B8C656024DB';
SELECT HEX(UUID_TO_BIN(@uuid, 1)), '1026BABA6CCD780C95645B8C656024DB';
SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,0),0), '6ccd780c-baba-1026-9564-5b8c656024db';
SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,1),1), '6ccd780c-baba-1026-9564-5b8c656024db';
包括来自 https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid-to-bin that demonstrate that the above code returns the exact same results as the 8.0 function. These functions are considered DETERMINISTIC as they always produce the same output for a given input. See https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html
的 SELECT 个样本
在 MySQL 4.0 及更高版本中,您可以像使用 MID
一样更改 UUID 的大小
SELECT MID(UUID(),1,32); # 32 characters long UUID
SELECT MID(UUID(),1,11); # 11 characters long UUID
正如@nickdnk 所指出的,您不应该这样做。 UUID 的总长度使它们独一无二。剥离其中的一部分可能会导致非唯一值。
我不明白为什么
SELECT UUID();
Returns 类似于:
3f06af63-a93c-11e4-9797-00505690773f
但是如果我将它插入一个二进制 (16) 字段(UUID() 函数),例如一个 BEFORE INSERT 触发器和 运行 一个 select,它 returns类似于:
0782ef48-a439-11
注意这两个UUID不是同一个数据
我意识到二进制和 UUID 字符串看起来不一样,但是 selected 数据不应该至少一样长吗?否则它怎么可能是唯一的?
存成char(36)是不是更好?我只需要它是唯一的以防止重复插入。它从不 select 编辑或用于联接。
编辑:
之前触发器会是这样的:
BEGIN
if NEW.UUID IS NULL THEN
NEW.UUID = UUID();
END IF
END
因此,作为对评论的回应。将 36 字符 UUID 存储为 binary(16) 的正确方法是以如下方式执行插入:
INSERT INTO sometable (UUID) VALUES
(UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")))
UNHEX
因为 UUID 已经是一个十六进制值。我们 trim (REPLACE
) 语句中的破折号将长度减少到 32 个字符(我们的 16 个字节表示为 HEX
)。显然,您可以在存储它之前的任何时候执行此操作,因此它不必由数据库处理。
您可以像这样检索 UUID:
SELECT HEX(UUID) FROM sometable;
以防万一有人遇到这个话题并且不确定它是如何工作的。
请记住:如果您使用 UUID 选择行,在条件 :
上使用UNHEX()
SELECT * FROM sometable WHERE UUID = UNHEX('3f06af63a93c11e4979700505690773f');
或 literal notation(如 Alexis Wilke 所述):
SELECT * FROM sometable WHERE UUID = 0x3f06af63a93c11e4979700505690773f;
而不是HEX()
列:
SELECT * FROM sometable WHERE HEX(UUID) = '3f06af63a93c11e4979700505690773f';
最后一个解决方案虽然可行,但需要 MySQL HEX
读取所有 UUID,然后才能确定哪些行匹配。效率很低。
编辑:如果您使用的是 MySQL 8,您应该查看 SlyDave 的回答中提到的 UUID 函数。这个答案仍然是正确的,但它没有优化可以使用这些函数本机完成的 UUID 索引。如果你在 < MySQL 8 上,你可以实现 Devon 的 polyfill,它提供与 MySQL.
以前版本相同的功能从 MySQL 8 开始,您可以使用两个新的 UUID functions:
BIN_TO_UUID
SELECT BIN_TO_UUID(uuid, true) AS uuid FROM foo; -- 3f06af63-a93c-11e4-9797-00505690773f
UUID_TO_BIN
INSERT INTO foo (uuid) VALUES (UUID_TO_BIN('3f06af63-a93c-11e4-9797-00505690773f', true));
此方法还支持重新排列 uuid 的时间部分以增强索引性能(通过按时间顺序排列),只需将第二个参数设置为 true - 这仅适用于 UUID1。
如果您在 UUID_TO_BIN
标志上使用 true
来提高索引性能(推荐),您还必须在 BIN_TO_UUID
上设置它,否则它无法正确转换回来。
有关详细信息,请参阅文档。
我正在使用 MariaDB,所以 BIN_TO_UUID
函数系列不存在。无论如何,我设法得到了相应的值。
bin -> hex
这里,uuid
是一个uuid的binary(16)值;您将使用下面的值来 SELECT 它的可读版本。
LOWER(CONCAT(
SUBSTR(HEX(uuid), 1, 8), '-',
SUBSTR(HEX(uuid), 9, 4), '-',
SUBSTR(HEX(uuid), 13, 4), '-',
SUBSTR(HEX(uuid), 17, 4), '-',
SUBSTR(HEX(uuid), 21)
))
hex -> bin
此处,cc6e6d97-5501-11e7-b2cb-ceedca613421
是 UUID 的可读版本,您将在 WHERE 子句中使用下面的值来查找它。
UNHEX(REPLACE('cc6e6d97-5501-11e7-b2cb-ceedca613421', '-', ''))
干杯
其他答案正确。 UUID()
函数 returns 一个 36 个字符的字符串,需要使用显示的函数(UNHEX()
或在较新的平台上,UUID_TO_BIN()
)进行转换。
但是,如果您使用自己的软件创建 UUID,则可以改用 Hexadecimal Literal notation。
所以我会在 MySQL UUID()
函数中使用以下内容:
INSERT INTO sometable (id) VALUES (UNHEX(REPLACE(UUID(), '-', ''))); -- all versions
INSERT INTO sometable (id) VALUES (UUID_TO_BIN(UUID()); -- since v8.0
但如果我生成自己的 UUID,请使用它;
INSERT INTO sometable (id) VALUES 0x3f06af63a93c11e4979700505690773f;
同样,您可以在 WHERE
子句中使用十六进制文字:
SELECT * FROM sometable WHERE id = 0x3f06af63a93c11e4979700505690773f;
如果您不必每次都将数据转换为 UUID 字符串,这样会更快。
注意:'0xaBc
中的'x'
区分大小写。然而,十六进制数字不是。
BIN_TO_UUID 的 Polyfill 和 MySQL 的 UUID_TO_BIN 5 以及 swap_flag 参数。
DELIMITER $$
CREATE FUNCTION BIN_TO_UUID(b BINARY(16), f BOOLEAN)
RETURNS CHAR(36)
DETERMINISTIC
BEGIN
DECLARE hexStr CHAR(32);
SET hexStr = HEX(b);
RETURN LOWER(CONCAT(
IF(f,SUBSTR(hexStr, 9, 8),SUBSTR(hexStr, 1, 8)), '-',
IF(f,SUBSTR(hexStr, 5, 4),SUBSTR(hexStr, 9, 4)), '-',
IF(f,SUBSTR(hexStr, 1, 4),SUBSTR(hexStr, 13, 4)), '-',
SUBSTR(hexStr, 17, 4), '-',
SUBSTR(hexStr, 21)
));
END$$
CREATE FUNCTION UUID_TO_BIN(uuid CHAR(36), f BOOLEAN)
RETURNS BINARY(16)
DETERMINISTIC
BEGIN
RETURN UNHEX(CONCAT(
IF(f,SUBSTRING(uuid, 15, 4),SUBSTRING(uuid, 1, 8)),
SUBSTRING(uuid, 10, 4),
IF(f,SUBSTRING(uuid, 1, 8),SUBSTRING(uuid, 15, 4)),
SUBSTRING(uuid, 20, 4),
SUBSTRING(uuid, 25))
);
END$$
DELIMITER ;
--
-- Tests to demonstrate that it works correctly. These are the values taken from
-- https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid-to-bin
--
-- If you run these SELECTs using the above functions, the
-- output of the two columns should be exactly identical in all four cases.
SET @uuid = '6ccd780c-baba-1026-9564-5b8c656024db';
SELECT HEX(UUID_TO_BIN(@uuid, 0)), '6CCD780CBABA102695645B8C656024DB';
SELECT HEX(UUID_TO_BIN(@uuid, 1)), '1026BABA6CCD780C95645B8C656024DB';
SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,0),0), '6ccd780c-baba-1026-9564-5b8c656024db';
SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,1),1), '6ccd780c-baba-1026-9564-5b8c656024db';
包括来自 https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid-to-bin that demonstrate that the above code returns the exact same results as the 8.0 function. These functions are considered DETERMINISTIC as they always produce the same output for a given input. See https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html
的 SELECT 个样本在 MySQL 4.0 及更高版本中,您可以像使用 MID
一样更改 UUID 的大小SELECT MID(UUID(),1,32); # 32 characters long UUID
SELECT MID(UUID(),1,11); # 11 characters long UUID
正如@nickdnk 所指出的,您不应该这样做。 UUID 的总长度使它们独一无二。剥离其中的一部分可能会导致非唯一值。