Я видел другие подобные вопросы о SO, но на то, что я спрашиваю здесь, там нет ответа.

У меня в таблице есть поле GUID, которое является первичным ключом.

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

Итак, я создал эту таблицу:

CREATE TABLE `myTable` (
  `id` int(6) NOT NULL,
  `first_name` varchar(64) NOT NULL,
  `last_name` varchar(64) NOT NULL,
  `GUID` char(40) NOT NULL,
   PRIMARY KEY(`GUID`) 

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

DELIMITER //
CREATE TRIGGER `t_GUID` BEFORE INSERT ON `myTable`
 FOR EACH ROW begin
 SET new.GUID := (SELECT uuid());
END //
DELIMITER ;

Я вставил 4 новые записи в эту таблицу, и эти UUID добавлены в записи:

  • ae353781-9022-11ea - b775-1866daed31d4
  • ae353a23-9022-11ea - b775-1866daed31d4
  • ae353b4e - 9022-11ea - b775-1866daed31d4
  • ae353c26-9022-11ea - b775-1866daed31d4

За исключением 3 цифр это в основном один и тот же UUID.

Как мне сгенерировать совершенно разные UUID, которые являются уникальными для таблицы при вставке новых записей?

1
Duck 7 Май 2020 в 08:31

2 ответа

Лучший ответ

Чтобы ответить на ваш вопрос, да, guid или uuid не предназначены для того, чтобы их было трудно предсказать. Он предназначен только для того, чтобы быть уникальным, что является достаточно сложной задачей.

Наличие таких больших первичных ключей действительно займет место, что снижает производительность.

Я не рекомендовал бы это для чего-нибудь кроме крайнего средства. Обычно люди используют guid для ключей, когда планируют заранее разделить данные на несколько таблиц.

Еще один аргумент против этого заключается в том, что запутывание не является безопасностью. Если существует проблема с точки зрения безопасности, когда кто-то видит что-то, что ему не следует, потому что он получил доступ, например, к URL-адресу с id=3, то такая же проблема существует, если URL-адрес id=ae353c26-9022-11ea-b775-1866daed31d4. Приложение не должно позволять кому-либо получать доступ к id=3, если у него нет доступа к нему.

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

Вы можете использовать uuid, объединенный с некоторыми данными из строки, и, возможно, временную метку, и что-то случайное, и, например, выполнить это через sha1 (). Это создаст большую 40-символьную шестнадцатеричную строку.

Существует вероятность столкновения, поэтому вы, вероятно, захотите проверить и восстановиться после этого.

CREATE TABLE `myTable` (
  `id` int(6) NOT NULL,
  `first_name` varchar(64) NOT NULL,
  `last_name` varchar(64) NOT NULL,
  `GUID` char(40) NOT NULL,
   PRIMARY KEY(`GUID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

DELIMITER //

CREATE TRIGGER `t_GUID` BEFORE INSERT ON `myTable`
 FOR EACH ROW begin
 SET new.GUID := (SELECT SHA1(CONCAT(new.first_name, RAND(), UUID(), new.last_name, NOW())));
END //
DELIMITER ;
3
gview 7 Май 2020 в 06:41

Функция uuid () генерирует UUIDv1, который определен довольно предсказуемым образом. Если вы генерируете множество новых значений очень быстро, они будут отличаться лишь на несколько битов, но они все равно будут гарантированно уникальными.

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

Кроме того: вы можете рассмотреть возможность хранения UUID как BINARY (16) для экономии места и повышения эффективности поиска. Вы можете использовать сгенерированный столбец, чтобы получить текстовую версию, если вам это нужно внутри БД для устранения неполадок.

0
StephenS 24 Май 2020 в 16:17