关于mysql:插入并选择UUID作为二进制文件(16)

Inserting and selecting UUIDs as binary(16)

我不明白为什么

返回类似:

1
3f06af63-a93c-11e4-9797-00505690773f

但是,如果我使用例如BEFORE INSERT触发器将其插入binary(16)字段(UUID()函数)中并运行select,它将返回类似以下内容的结果:

1
0782ef48-a439-11

请注意,这两个UUID是不同的数据。

我意识到二进制文件和UUID字符串看起来不一样,但是所选数据至少应该不一样长吗? 否则,它怎么可能同样具有唯一性?

将其存储为char(36)更好吗? 我只需要它是唯一的即可防止重复插入。 永远不会选择它或将其用于联接。

编辑:

触发之前是这样的:

1
2
3
4
5
6
7
8
9


因此,作为对评论的回应。将36个字符的UUID存储为binary(16)的正确方法是以如下方式执行插入:

1
2
INSERT INTO sometable (UUID) VALUES
       (UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f","-","")))

UNHEX,因为UUID已经是十六进制值。我们对语句中的破折号进行修整(REPLACE),以将长度减小到32个字符(我们的16个字节表示为HEX)。显然,您可以在存储它之前随时进行此操作,因此数据库不必处理它。

您可以这样检索UUID:

1
SELECT HEX(UUID) FROM sometable;

以防万一有人碰到这个线程并且不确定它是如何工作的。

请记住:如果要使用UUID选择行,请在以下情况下使用UNHEX()

1
SELECT * FROM sometable WHERE UUID = UNHEX('3f06af63a93c11e4979700505690773f');

而不是该列上的HEX()

1
SELECT * FROM sometable WHERE HEX(UUID) = '3f06af63a93c11e4979700505690773f';

第二种解决方案在起作用的同时,要求MySQL HEX定义所有UUID,然后才能确定哪些行匹配。这是非常低效的。

编辑:如果您使用的是MySQL 8,则应查看SlyDave答案中提到的UUID函数。这个答案仍然是正确的,但是它没有优化可以使用这些函数本地完成的UUID索引。如果您使用的是


从MySQL 8开始,您可以使用两个新的UUID函数:

此方法还支持重新排列uuid的时间分量以增强索引性能(通过按时间顺序对其进行排序),只需将第二个参数设置为true即可-这仅适用于UUID1。

如果将UUID_TO_BIN上的true标志用于索引性能(推荐),则还必须将其设置在BIN_TO_UUID上,否则将无法正确转换回原值。

有关更多详细信息,请参见文档。

  • https://dev.mysql.com/doc/refman/8.0/zh-CN/miscellaneous-functions.html#function_uuid-to-bin
  • http://mysqlserverteam.com/mysql-8-0-uuid-support/


使用swap_flag参数的BIN_TO_UUID和MySQL 5的UUID_TO_BIN的Polyfill。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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-> hex

在这里,uuid是uuid的binary(16)值;您将使用下面的值选择它的可读版本。

1
2
3
4
5
6
7
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子句中使用以下值进行查找。

1
UNHEX(REPLACE('cc6e6d97-5501-11e7-b2cb-ceedca613421', '-', ''))

干杯


其他答案是正确的。 UUID()函数返回一个36个字符串,需要使用显示的函数(UNHEX()或在新平台上的UUID_TO_BIN())进行转换。

但是,如果您使用自己的软件创建UUID,则可以改用十六进制立即数表示法。

因此,我将对MySQL UUID()函数使用以下命令:

1
2
INSERT INTO sometable (id) VALUES (UNHEX(REPLACE(UUID(), '-', '')));  -- all versions
INSERT INTO sometable (id) VALUES (UUID_TO_BIN(UUID());               -- since v8.0

但是在我生成自己的UUID的情况下使用此方法;

1
INSERT INTO sometable (id) VALUES 0x3f06af63a93c11e4979700505690773f;

同样,您可以在WHERE子句中使用十六进制文字:

1
SELECT * FROM sometable WHERE id = 0x3f06af63a93c11e4979700505690773f;

如果您不必每次都将数据转换为UUID字符串,则速度会更快。

注意:'0xaBc中的'x'区分大小写。但是,十六进制数字不是。