Вопрос

Использую ли я varchar(36) или есть какие-то лучшие способы сделать это?

Это было полезно?

Решение

Мой администратор БД спросил меня, когда я спросил о наилучшем способе хранения GUID для моих объектов, почему мне нужно было хранить 16 байтов, когда я мог сделать то же самое в 4 байта с целым числом. Поскольку он поставил этот вызов передо мной, я подумал, что сейчас самое время упомянуть об этом. Как говорится ...

Вы можете сохранить guid в виде двоичного файла CHAR (16), если хотите наиболее оптимально использовать пространство для хранения.

Другие советы

Я бы сохранил его как символ (36).

Добавляя к ответу ThaBadDawg, используйте эти удобные функции (благодаря моему более мудрому коллеге), чтобы получить строку длиной 36 обратно в массив байтов, равный 16.

DELIMITER $

CREATE FUNCTION `GuidToBinary`(
    $Data VARCHAR(36)
) RETURNS binary(16)
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result BINARY(16) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Data = REPLACE($Data,'-','');
        SET $Result =
            CONCAT( UNHEX(SUBSTRING($Data,7,2)), UNHEX(SUBSTRING($Data,5,2)),
                    UNHEX(SUBSTRING($Data,3,2)), UNHEX(SUBSTRING($Data,1,2)),
                    UNHEX(SUBSTRING($Data,11,2)),UNHEX(SUBSTRING($Data,9,2)),
                    UNHEX(SUBSTRING($Data,15,2)),UNHEX(SUBSTRING($Data,13,2)),
                    UNHEX(SUBSTRING($Data,17,16)));
    END IF;
    RETURN $Result;
END

$

CREATE FUNCTION `ToGuid`(
    $Data BINARY(16)
) RETURNS char(36) CHARSET utf8
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result CHAR(36) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Result =
            CONCAT(
                HEX(SUBSTRING($Data,4,1)), HEX(SUBSTRING($Data,3,1)),
                HEX(SUBSTRING($Data,2,1)), HEX(SUBSTRING($Data,1,1)), '-', 
                HEX(SUBSTRING($Data,6,1)), HEX(SUBSTRING($Data,5,1)), '-',
                HEX(SUBSTRING($Data,8,1)), HEX(SUBSTRING($Data,7,1)), '-',
                HEX(SUBSTRING($Data,9,2)), '-', HEX(SUBSTRING($Data,11,6)));
    END IF;
    RETURN $Result;
END
$

CHAR (16) на самом деле является BINARY (16) , выберите предпочтительный вариант

Чтобы лучше следовать коду, возьмите пример с приведенным ниже порядковым номером GUID. (Недопустимые символы используются в иллюстративных целях - каждый из них содержит уникальный символ.) Функции преобразуют порядок байтов для достижения порядка битов для превосходной кластеризации индекса. Переупорядоченная направляющая показана под примером.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW

Черточки удалены:

123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW

char (36) будет хорошим выбором. Также можно использовать функцию MySQL UUID (), которая возвращает 36-символьный текстовый формат (шестнадцатеричный с дефисами), который можно использовать для получения таких идентификаторов из БД.

"Лучше" зависит от того, для чего вы оптимизируете.

Насколько вас волнует размер хранилища / производительность по сравнению спростота разработки?Что еще более важно - достаточно ли вы генерируете GUID или извлекаете их достаточно часто, чтобы это имело значение?

Если ответ будет "нет",, char(36) это более чем достаточно хорошо, и это упрощает хранение / выборку GUIDS.В противном случае, binary(16) это разумно, но вам придется полагаться на MySQL и / или выбранный вами язык программирования для преобразования туда и обратно из обычного строкового представления.

Двоичный код (16) будет лучше, чем использование varchar (32).

Подпрограмма GuidToBinary, опубликованная KCD, должна быть настроена так, чтобы учитывать расположение битов временной метки в строке GUID. Если строка представляет UUID версии 1, как и те, которые возвращаются подпрограммой mysql uuid (), то временные компоненты включаются в буквы 1-G, исключая D.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678 = least significant 4 bytes of the timestamp in big endian order
9ABC     = middle 2 timestamp bytes in big endian
D        = 1 to signify a version 1 UUID
EFG      = most significant 12 bits of the timestamp in big endian

Когда вы преобразуете в двоичный файл, лучшим порядком для индексации будет: EFG9ABC12345678D + остальные.

Вы не хотите менять местами 12345678 на 78563412, потому что старший порядок байтов уже дает наилучший порядок байтов двоичного индекса. Однако вы хотите, чтобы наиболее значимые байты были перемещены перед младшими байтами. Следовательно, EFG идет первым, затем идут средние и младшие биты. Создайте дюжину UUID с помощью uuid () в течение минуты, и вы должны увидеть, как этот порядок дает правильный ранг.

select uuid(), 0
union 
select uuid(), sleep(.001)
union 
select uuid(), sleep(.010)
union 
select uuid(), sleep(.100)
union 
select uuid(), sleep(1)
union 
select uuid(), sleep(10)
union
select uuid(), 0;

/* output */
6eec5eb6-9755-11e4-b981-feb7b39d48d6
6eec5f10-9755-11e4-b981-feb7b39d48d6
6eec8ddc-9755-11e4-b981-feb7b39d48d6
6eee30d0-9755-11e4-b981-feb7b39d48d6
6efda038-9755-11e4-b981-feb7b39d48d6
6f9641bf-9755-11e4-b981-feb7b39d48d6
758c3e3e-9755-11e4-b981-feb7b39d48d6 

Первые два UUID были сгенерированы ближе всего по времени. Они различаются только в последних 3 полубайтах первого блока. Это наименее значимые биты метки времени, что означает, что мы хотим сдвинуть их вправо, когда преобразуем это в индексируемый байтовый массив. В качестве встречного примера последний идентификатор является самым текущим, но алгоритм обмена KCD поместит его перед третьим идентификатором (3e перед постоянным током, последние байты из первого блока).

Правильный порядок индексации:

1e497556eec5eb6... 
1e497556eec5f10... 
1e497556eec8ddc... 
1e497556eee30d0... 
1e497556efda038... 
1e497556f9641bf... 
1e49755758c3e3e... 

Дополнительную информацию см. в этой статье: http://mysql.rjweb.org/doc.php. / UUID

*** обратите внимание, что я не отделяю ниппель версии от старших 12 бит метки времени. Это D клев от вашего примера. Я просто бросаю это впереди. Так что моя двоичная последовательность заканчивается тем, что DEFG9ABC и так далее. Это означает, что все мои индексированные UUID начинаются с одного и того же куска. Статья делает то же самое.

Для тех, кто только что наткнулся на это, теперь есть гораздо лучшая альтернатива, согласно исследованию Percona.

Он состоит из реорганизации блоков UUID для оптимальной индексации, а затем преобразования в двоичный файл для уменьшения объема памяти.

Читать статью полностью здесь

Я бы предложил использовать приведенные ниже функции, так как те, что упоминаются @ bigh_29, превращают мои направляющие в новые (по причинам, которые я не понимаю). Кроме того, они немного быстрее в тех тестах, которые я проводил на своих столах. https://gist.github.com/damienb/159151

DELIMITER |

CREATE FUNCTION uuid_from_bin(b BINARY(16))
RETURNS CHAR(36) DETERMINISTIC
BEGIN
  DECLARE hex CHAR(32);
  SET hex = HEX(b);
  RETURN LOWER(CONCAT(LEFT(hex, 8), '-', MID(hex, 9,4), '-', MID(hex, 13,4), '-', MID(hex, 17,4), '-', RIGHT(hex, 12)));
END
|

CREATE FUNCTION uuid_to_bin(s CHAR(36))
RETURNS BINARY(16) DETERMINISTIC
RETURN UNHEX(CONCAT(LEFT(s, 8), MID(s, 10, 4), MID(s, 15, 4), MID(s, 20, 4), RIGHT(s, 12)))
|

DELIMITER ;

если у вас есть значение char / varchar, отформатированное как стандартный GUID, вы можете просто сохранить его как BINARY (16), используя простой CAST (MyString AS BINARY16), без всех этих ошеломляющих последовательностей CONCAT + SUBSTR.

BINARY (16) поля сравниваются / сортируются / индексируются намного быстрее, чем строки, а также занимают в два раза меньше места в базе данных

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top