我不明白为什么
SELECT UUID();
返回类似:
3f06af63-a93c-11e4-9797-00505690773f
但是,如果我使用 BEFORE INSERT 触发器将其插入二进制(16)字段(UUID()函数)并运行选择,它会返回类似以下内容:
0782ef48-a439-11
注意,这两个UUID不是相同的数据。
我意识到二进制和 UUID 字符串看起来不一样,但是所选数据不应该至少一样长吗?否则它怎么可能同样可能是唯一的?
将其存储为 char(36) 是否更好?我只需要它是唯一的以防止重复插入。它永远不会被选择或用于连接。
编辑:
触发之前会是这样的:
BEGIN
if NEW.UUID IS NULL THEN
NEW.UUID = UUID();
END IF
END
所以,作为对评论的回应。将 36 字符 UUID 存储为二进制 (16) 的正确方法是以如下方式执行插入:
INSERT INTO sometable (UUID) VALUES
(UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")))
UNHEX
因为 UUID 已经是十六进制值。我们修剪 (REPLACE
) 语句中的破折号,将长度减少到 32 个字符(我们的 16 个字节表示为 HEX
)。显然,您可以在存储之前随时执行此操作,因此不必由数据库处理。
您可以像这样检索 UUID:
SELECT HEX(UUID) FROM sometable;
以防万一有人遇到此线程并且不确定它是如何工作的。
请记住:如果您使用 UUID 选择行,请在条件上使用
UNHEX()
:
SELECT * FROM sometable WHERE UUID = UNHEX('3f06af63a93c11e4979700505690773f');
或文字符号(如 Alexis Wilke 提到的):
SELECT * FROM sometable WHERE UUID = 0x3f06af63a93c11e4979700505690773f;
而不是
HEX()
在专栏上:
SELECT * FROM sometable WHERE HEX(UUID) = '3f06af63a93c11e4979700505690773f';
最后一个解决方案虽然有效,但要求 MySQL
HEX
先检查所有 UUID,然后才能确定哪些行匹配。效率太低了
编辑:如果您使用的是 MySQL 8,您应该查看 SlyDave 的回答中提到的 UUID 函数。这个答案仍然是正确的,但它没有优化 UUID 索引,而 UUID 索引可以使用这些函数本机完成。如果你在 < MySQL 8 or MariaDB, you can implement Devon's polyfill, which provides identical functionality on previous versions of MySQL.
从 MySQL 8 开始,您可以使用两个新的 UUID 函数:
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。
如果您在
true
标志上使用 UUID_TO_BIN
来提高索引性能(推荐),则还必须将其设置为 BIN_TO_UUID
,否则它将无法正确转换回来。
请参阅文档了解更多详细信息。
使用 swap_flag 参数对 MySQL 5 或 MariaDB 的 BIN_TO_UUID 和 UUID_TO_BIN 进行 Polyfill。
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 的 SELECT 示例,证明上述代码返回与以下完全相同的结果8.0功能。这些函数被认为是确定性的,因为它们对于给定的输入总是产生相同的输出。请参阅https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html
我正在使用 MariaDB,因此
BIN_TO_UUID
函数系列不存在。无论如何我设法得到了相应的值。
bin -> 十六进制
这里,
uuid
是uuid的二进制(16)值;您将使用下面的值来选择它的可读版本。
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)
))
十六进制 -> bin
此处,
cc6e6d97-5501-11e7-b2cb-ceedca613421
是 UUID 的可读版本,您将在 WHERE 子句中使用以下值来查找它。
UNHEX(REPLACE('cc6e6d97-5501-11e7-b2cb-ceedca613421', '-', ''))
干杯
其他答案都是正确的。
UUID()
函数返回 36 个字符的字符串,需要使用所示函数进行转换(UNHEX()
,或者在较新的平台上,UUID_TO_BIN()
)。
但是,如果您使用自己的软件创建 UUID,则可以使用 十六进制文字表示法。
所以我将使用以下 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 字符串,那么速度会更快。
注意:
'x'
中的'0xaBc
区分大小写。然而,十六进制数字不是。
在 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 的总长度使它们独一无二。剥离其中的一部分可能会导致非唯一值。