Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL generate UUID() for multiple rows

I'm trying to add UUIDs to some tables in some of my MySQL databases (MySQL 5.7.9). First of all, I start by adding a column to receive the UUIDs:

ALTER TABLE `mytable` ADD COLUMN `Uuid` BINARY(16) DEFAULT NULL;

Then, for all entries that are already in the table, I generate UUIDs (since every entry in the DB will have received a NULL value in it's UUID field.

UPDATE `mytable` SET Uuid= unhex(replace(uuid(),'-','')) WHERE Uuid IS NULL;

Now, the thing is that I get some very weird behaviour by doing this; on some of my databases, every UUID generated is unique (as expected). However, on other databases, all generated UUIDs are identical (not similar, identical).

I suspect that this is due to the MySQL query optimiser, since behaviour is not consistent between different database instances (all on MySQL 5.7.9). However, I have no clue how to solve this issue.

So, MySQL gurus, am I doing something wrong?

like image 363
Paws Avatar asked Aug 11 '17 11:08

Paws


3 Answers

I had the same problem, but the solution was a later answer to the linked question. I had a default character set of utf8mb4, and the theory is that it implicitly converts uuid()'s utf8 result to a constant string, before the sql executes. Converting the other parameters to utf8 avoids that:

UPDATE `mytable` SET Uuid= unhex(replace(uuid(), _utf8'-', _utf8'')) WHERE Uuid IS NULL;

The later answer links to the relevant (not a) bug report. This SO issue looks related.

like image 86
J. David Beutel Avatar answered Nov 13 '22 19:11

J. David Beutel


The solution in the link from @TimBiegelsen works.

I declared a function to generate UUID according to v4 standard.

CREATE FUNCTION uuid_v4()
    RETURNS BINARY(16)
BEGIN
    -- Generate 8 2-byte strings that we will combine into a UUIDv4
    SET @h1 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h2 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h3 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h6 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h7 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h8 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');

    -- 4th section will start with a 4 indicating the version
    SET @h4 = CONCAT('4', LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));

    -- 5th section first half-byte can only be 8, 9 A or B
    SET @h5 = CONCAT(HEX(FLOOR(RAND() * 4 + 8)),
                LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));

    -- Build the complete UUID
    RETURN UNHEX(LOWER(CONCAT(@h1, @h2, @h3, @h4, @h5, @h6, @h7, @h8)));
END;;
DELIMITER ;
like image 29
Paws Avatar answered Nov 13 '22 19:11

Paws


Best solution is:

UPDATE mytable SET Uuid= MID(UUID(),1,36) WHERE Uuid IS NULL;

like image 1
Jairo Bernal Avatar answered Nov 13 '22 17:11

Jairo Bernal