插入和选择UUID为二进制(16)

nic*_*dnk 24 mysql binary uuid

我不明白为什么

SELECT UUID();
Run Code Online (Sandbox Code Playgroud)

返回类似于:

3f06af63-a93c-11e4-9797-00505690773f
Run Code Online (Sandbox Code Playgroud)

但是如果我将它插入二进制(16)字段(UUID()函数)并使用例如BEFORE INSERT触发器并运行select,它将返回如下内容:

0782ef48-a439-11
Run Code Online (Sandbox Code Playgroud)

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

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

将它存储为char(36)更好吗?我只需要它是唯一的,以防止重复插入.它永远不会被选中或用于连接.

编辑:

在触发之前会是这样的:

BEGIN

if NEW.UUID IS NULL THEN

NEW.UUID = UUID();

END IF

END
Run Code Online (Sandbox Code Playgroud)

nic*_*dnk 64

所以,作为对评论的回应.将36-char UUID存储为二进制(16)的正确方法是以下列方式执行插入:

INSERT INTO sometable (UUID) VALUES
       (UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")))
Run Code Online (Sandbox Code Playgroud)

UNHEX因为UUID已经是一个hexed值.我们修剪(REPLACE)语句中的破折号,使长度减少到32个ASCII字符(我们的16个字节表示为HEX).显然,您可以在存储之前随时执行此操作,因此不必由数据库处理.

您可以像这样检索UUID:

SELECT HEX(UUID) FROM sometable;
Run Code Online (Sandbox Code Playgroud)

以防万一有人遇到这个帖子并且不确定这是如何工作的.

请记住:如果您使用UUID选择一行,请使用UNHEX()以下条件:

SELECT * FROM sometable WHERE UUID = UNHEX('3f06af63a93c11e4979700505690773f');
Run Code Online (Sandbox Code Playgroud)

而不是HEX()专栏:

SELECT * FROM sometable WHERE HEX(UUID) = '3f06af63a93c11e4979700505690773f';
Run Code Online (Sandbox Code Playgroud)

第二种解决方案虽然有效,但要求MySQL HEX确定所有UUID,然后才能确定哪些行匹配.这是非常低效的.

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


Sly*_*ave 24

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

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

如果使用trueon UUID_TO_BIN标志来建立索引性能(推荐),则还必须将其设置为on,BIN_TO_UUID否则将无法正确转换.

有关详细信息,请参阅文档.

  • @friek108 - 如何使从 MySQL 迁移到 PostgreSQL 比将代码库更改为 UUID 插入更容易?我真的不明白那是如何运作的。你能详细说明一下吗? (4认同)
  • 经过大量研究,我们决定从 MySQL 迁移到 PostgreSQL,因为它们有一个 UUID 数据类型(就像自动增量,它自动插入,更重要的是,您可以直接使用字符串读取它)。否则,我们必须使用 mysql 5.7 或 8 的 id 重构我们有更新或读取的整个代码库。 (2认同)

Dev*_*von 16

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

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';
Run Code Online (Sandbox Code Playgroud)

包括来自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


Ale*_*lke 7

其他答案是正确的。该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
Run Code Online (Sandbox Code Playgroud)

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

INSERT INTO sometable (id) VALUES 0x3f06af63a93c11e4979700505690773f;
Run Code Online (Sandbox Code Playgroud)

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

SELECT * FROM sometable WHERE id = 0x3f06af63a93c11e4979700505690773f;
Run Code Online (Sandbox Code Playgroud)

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

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


Ala*_*blo 6

我正在使用MariaDB,因此BIN_TO_UUID功能族不存在。无论如何,我设法获得了相应的值。

bin -> hex

这里uuid是uuid的binary(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)
))
Run Code Online (Sandbox Code Playgroud)

hex -> bin

cc6e6d97-5501-11e7-b2cb-ceedca613421是UUID的可读版本,您将在WHERE子句中使用下面的值来寻找它。

UNHEX(REPLACE('cc6e6d97-5501-11e7-b2cb-ceedca613421', '-', ''))
Run Code Online (Sandbox Code Playgroud)

干杯

  • 你完全正确。我也不知道,去我想的把手。谢谢 :) (3认同)