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

thigvfpy  于 2023-08-02  发布在  Mysql
关注(0)|答案(6)|浏览(136)

我不明白为什么

SELECT UUID();

字符串
返回类似于以下内容的内容:

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


但是,如果我用BEFORE INSERT触发器将它插入到一个二进制(16)字段(UUID()函数)中,然后运行select,它会返回如下内容:

0782ef48-a439-11


注意,这两个UUID不是相同的数据。
我意识到二进制和UUID字符串看起来并不相同,但所选数据至少应该一样长吧?否则它怎么可能是唯一的呢?
把它存储为char(36)更好吗?我只需要它是唯一的,以防止重复插入。它永远不会被选中或用于联接。
编辑:
触发器之前的代码如下:

BEGIN

if NEW.UUID IS NULL THEN

NEW.UUID = UUID();

END IF

END

bqucvtff

bqucvtff1#

作为对评论的回应。将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');


或者literal notation(正如Alexis Wilke所提到的):

SELECT * FROM sometable WHERE UUID = 0x3f06af63a93c11e4979700505690773f;

且列上的NOT HEX()

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


最后一个解决方案,当它工作时,要求MySQL HEX在确定哪些行匹配之前es所有UUID。效率很低。
编辑:如果你使用的是MySQL 8,你应该看看SlyDave的回答中提到的UUID函数。这个答案仍然是正确的,但它没有优化UUID索引,而UUID索引可以使用这些函数在本机完成。如果你使用的是< MySQL 8或MariaDB,你可以实现德文郡的polyfill,它提供了与以前版本的MySQL相同的功能。

c8ib6hqw

c8ib6hqw2#

从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 -这只适用于UUID 1。
如果您使用true on UUID_TO_BIN标志来提高索引性能(推荐),则还必须在BIN_TO_UUID上设置它,否则它将无法正确转换回来。
更多详细信息请参见文档。

bjg7j2ky

bjg7j2ky3#

使用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';

字符串
其中包括来自www.example.com的SELECT示例https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid-to-bin,这些示例表明上述代码返回的结果与8.0函数完全相同。这些函数被认为是确定性的,因为它们总是为给定的输入产生相同的输出。参见https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html

axr492tv

axr492tv4#

我正在使用MariaDB,所以BIN_TO_UUID函数家族不存在。无论如何,我设法得到了相应的值。
bin -> hex
这里,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)
))

字符串
hex -> bin
这里,cc6e6d97-5501-11e7-b2cb-ceedca613421是UUID的可读版本,您将在WHERE子句中使用下面的值来查找它。

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


干杯

aamkag61

aamkag615#

其他答案都是正确的。UUID()函数返回一个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'区分大小写。然而,十六进制数字不是。*
nc1teljy

nc1teljy6#

在MySQL4.0及以上版本中,您可以像使用MID一样更改UUID的大小

SELECT MID(UUID(),1,32); # 32 characters long UUID
SELECT MID(UUID(),1,11); # 11 characters long UUID

字符串
正如@nickdnk指出的那样,你不应该这样做。UUID的总长度使它们唯一。对其中的一部分进行条带化可能会导致非唯一值。

相关问题