Заменить функцию MySQL UUID версии 1?

Контекст

Веб-приложение, PHP 5, MySQL 5.0.91

Проблема

Недавно я переключился с использования автоинкрементного целого на UUID в качестве первичного ключа для некоторых моих таблиц. При генерации UUID через MySQL UUID() они очень похожи друг на друга:

| uuid                                 |
----------------------------------------
| 1e5988da-afec-11e1-9877-5464f7aa6d24 |
| 408092aa-afad-11e1-9877-5464f7aa6d24 |
  ^------^   ^^
  1      8   11-12

Как вы можете видеть, только первые 8 символов, а 11 и 12 - разные. Я понимаю, что в UUID версии 1 используется метка времени и аппаратный MAC-адрес для генерации UUID. Тем не менее, я не решаюсь использовать версию 1 из-за этих сходств (и того факта, что MAC-адрес в моем случае никогда не изменится). Кроме того, если MAC-адрес никогда не изменяется, большая часть UUID бесполезна и тратит впустую пространство.

Моя пользовательская функция UUID

В качестве эксперимента я написал пользовательский UUID-генератор в PHP:

public static function GenerateUUID()
{
    return
    substr(sha1(Account::GetUsername() . Account::GetUserID()), 18, 8) . "-" .
    substr(md5(time()), rand() % 28, 4) . "-" . 
    substr(md5(date("Y")), rand() % 28, 4) . "-" . 
    substr(sha1(rand()), 20, 4) . "-" . 
    substr(sha1(rand() % PHP_INT_MAX), 17, 12);
}

Образец результатов:

| uuid                                 |
----------------------------------------
| 574d18c2-5080-bac9-5597-45435f363ea1 |
| 574d18c2-30d4-8b5b-4ffd-001744d3d287 |

Здесь первые 8 символов идентичны для одного и того же пользователя. Это было предназначено, но не нужно.

Вопрос

Есть ли предпочтительный/рекомендуемый способ создания UUID Версии 4 или Версии 5 в запросе MySQL?

Если нет, допустимо ли генерировать пользовательский UUID в PHP (как указано выше), который не соответствует спецификации?

Ограничения

  • Я использую общий план хостинга с доступом к командной строке, но не могу изменить существующую установку MySQL.
  • Я бы предпочел избегать сторонних пакетов/библиотек.

Примечания

  • Я не выполняю и не выполняю слияние, синхронизацию или другие операции, для которых требуется GUID, содержащий MAC-адрес. Это не проблема.

Ответ 1

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

Фактически, V1 UUID более подходит, чем V4, если вы используете UUID, как идентификатор таблицы, потому что он использует MAC-адрес и отметку времени для предотвращения столкновений. В V4 такого механизма нет, хотя вам практически не нужно слишком беспокоиться о столкновениях:) Вы должны использовать V4 UUID вместо V1, если вам нужно, чтобы ваш UUID был непредсказуемым.

Также обратите внимание, что составление, например, случайных значений 4x4 байтов, может быть не таким же, как создание 16-байтового случайного значения. Как всегда с криптографией и хаотичностью: я бы отказался от реализации собственной процедуры UUID:: V4.

Если вы установили на свой компьютер, вы можете использовать пакет php-uuid.

Пример кода (который можно использовать в вашем приложении как есть) можно найти здесь: http://rommelsantor.com/clog/2012/02/23/generate-uuid-in-php/

Используйте его следующим образом:

$uuid = uuid_create(1);

Пользователи, которые могут устанавливать пакеты на своем веб-сервере, могут установить требуемый пакет, например: (здесь для ubuntu)

apt-get install php5-dev uuid-dev
pecl install uuid

Ответ 2

На самом деле довольно хорошая идея оценить наличие "похожих частей". Это позволит вам использовать MAC-адрес, чтобы иметь возможность идентифицировать "какой из моих серверов сгенерировал этот UUID?"... что будет чрезвычайно полезно при переносе данных между удаленными точками. Вы можете даже сделать "это мои тестовые данные" и "это мои производственные данные" таким образом.

В PHP имеется большое количество библиотек UUID-генераторов.

Здесь одна вещь PECL/PEAR (я ее никогда не использовал):

http://pecl.php.net/package/uuid

В рамках CakePHP:

http://api.cakephp.org/class/string#method-Stringuuid (cake 2.x) http://api13.cakephp.org/class/string#method-Stringuuid (cake 1.3)

Последняя опция генератора:

Рассмотрим использование программы командной строки Linux uuid, которая имеет флаг управления версиями -v и связанные с ним параметры, и используя это для подачи вашей базы данных. Это неэффективно, но по крайней мере вам не придется писать свои собственные функции генератора.

http://linux.die.net/man/1/uuid - справочная страница

(пакет uuid для Debian)

Я заметил, что для версий пространства имен вы будете генерировать множество "длинных человеческих имен" для преобразования в uuids. Если у вас нет конфликтов с ними, это может быть очень мило. Например, пользователи регистрируются с адресами электронной почты... Получите v5 uuid для этого адреса электронной почты... вы всегда найдете этого человека! Кажется, что каждый раз выплевывает один и тот же UUID, и UUID будет представлять уникальные отношения, которые [email protected] имеет с example.com в качестве члена.

uuid -v5 ns:URL "http://example.com/member/[email protected]/"

Комментарий:

Кроме того, UUID, как вы их сохраняете, CHAR (36)? Вы можете пожалеть о том, что после того, как операторы сравнения вступили в игру.

Postgres будет рассматривать UUID как 128-битные значения (и, предположительно, делать оптимизированные двоичные операции), тогда как решение MYSQL CHAR (36) рассматривает 36 байт = 288-битные ANSI или 576-битные UTF8 плюс-минус бит/байты для ведения офиса (и, предположительно, выполняют гораздо более медленные многобайтовые char -by-multibyte- char строковые процедуры).

Я действительно много внимания уделял вопросам для MySQL плюс UUID... и я пришел к выводу, что вы хотите записать хранимую функцию, которая преобразует шестнадцатеричное представление в двоичное представление для хранения, и что заставит все операторы "select" требовать преобразования обратно в шестнадцатеричное представление... и кто знает, насколько эффективно любой из них будет... поэтому, наконец, просто переключитесь на Postgres. XD

Если вы хотите переключиться на Postgres, постарайтесь быть очень осторожным при установке на своем существующем сервере (серверах), если это производственные серверы. Как и в... сделайте клон, чтобы проверить процесс миграции, прежде чем выполнять миграцию. Мне как-то удалось убить мою систему из-за того, что "установка этого пакета приведет к удалению большого количества важных других пакетов" (я не знаю, как установщик принял эти решения).

Кроме того, перейдите с Microsoft SQL для своего эквивалента GUID, если вы готовы в конце концов заплатить им много денег, чтобы управлять БД...

Выполнение UUID и MySQL в настоящий момент имеет тенденцию быть плохой идеей.