Mysql INSERT ... ON DUPLICATE KEY Повторно вставьте новый ключ - PullRequest
2 голосов
/ 04 апреля 2020

У меня такой запрос

INSERT INTO data(data_uuid, ...) VALUES(uuid_v4(), ...); 

Я прочитал о при повторном обновлении , но вместо обновления существующего столбца мне нужно переустановить строку с обновленный uuid. Существуют ли какие-либо конструкции, которые могут сделать жизнь более непринужденной?

Я продолжаю сталкиваться с такой ошибкой:

ERROR 1062 (23000): Duplicate entry '0f7018da-4df5-4e22-b995-3b3c3e4e85d3' for key 'data_uuid'

Чтобы устранить ее временно, я добавляю UUID, однако мне хотелось бы иметь более чистое решение, которое все еще держит меня с UUID.

Функция uuid выглядит следующим образом:

CREATE FUNCTION uuid_v4() RETURNS char(36) CHARSET latin1
BEGIN
    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');
    SET @h4 = CONCAT('4', LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));
    SET @h5 = CONCAT(HEX(FLOOR(RAND() * 4 + 8)),
                LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));
    RETURN LOWER(CONCAT(
        @h1, @h2, '-', @h3, '-', @h4, '-', @h5, '-', @h6, @h7, @h8
    ));
END 

1 Ответ

2 голосов
/ 05 апреля 2020

Как сказано в комментариях, если вы получаете коллизии с UUID только с миллионом строк (да, просто), это потому, что ваша генерация случайных uuid использует какой-то слабый генератор случайных чисел.

Поскольку вы сейчас опубликовали свой uuid_v4() функция, и она опирается на MySQL rand(), я могу объяснить, почему ваш код не работает.

Согласно mysql документы: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html

RAND () не должен быть идеальным генератором случайных чисел. Это быстрый способ генерирования случайных чисел по требованию, переносимый между платформами для одной и той же MySQL версии.

Это означает, что вы не можете использовать mysql для генерации uuid, в по крайней мере, не с RAND() функцией.

Вам нужно будет сгенерировать uuid за пределами mysql из возможных. Для этого есть несколько библиотек на многих языках:

Всегда проверяйте, использует ли выбранная вами библиотека криптографически безопасный генератор случайных чисел.

ОБНОВЛЕНИЕ

Можно генерировать безопасный UUID V4 на стороне MySQL, используя функцию random_bytes():

Эта функция возвращает двоичную строку случайных байтов len генерируется с использованием генератора случайных чисел из библиотеки SSL.

Таким образом, мы можем обновить вашу функцию следующим образом:

CREATE FUNCTION uuid_v4s()
    RETURNS CHAR(36)
BEGIN
    -- 1th and 2nd block are made of 6 random bytes
    SET @h1 = HEX(RANDOM_BYTES(4));
    SET @h2 = HEX(RANDOM_BYTES(2));

    -- 3th block will start with a 4 indicating the version, remaining is random
    SET @h3 = SUBSTR(HEX(RANDOM_BYTES(2)), 2, 3);

    -- 4th block first nibble can only be 8, 9 A or B, remaining is random
    SET @h4 = CONCAT(HEX(FLOOR(ASCII(RANDOM_BYTES(1)) / 64)+8),
                SUBSTR(HEX(RANDOM_BYTES(2)), 2, 3));

    -- 5th block is made of 6 random bytes
    SET @h5 = HEX(RANDOM_BYTES(6));

    -- Build the complete UUID
    RETURN LOWER(CONCAT(
        @h1, '-', @h2, '-4', @h3, '-', @h4, '-', @h5
    ));
END

Эта функция должна быть достаточно безопасной для использования, не заботясь о коллизиях, если только у вас очень большое количество строк.

Test

Я создал следующий сценарий тестирования: вставьте случайный UUID v4 в качестве первичного ключа для таблицы, пока не будет создано 40 000 000 строк. При обнаружении коллизии строка обновляется с шагом collisions столбец:

INSERT INTO test (uuid) VALUES (uuid_v4()) ON DUPLICATE KEY UPDATE collisions=collisions+1;

Сумма коллизий после 40 миллионов строк с каждой функцией:

+----------+----------------+
| RAND()   | RANDOM_BYTES() |
+----------+----------------+
|       55 |              0 |
+----------+----------------+

Число коллизий в обоих сценариях ios имеет тенденцию к увеличению с ростом числа строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...