"thaBadDawg" предлагает хороший ответ. Существует параллельная тема о переполнении стека, которая обсуждает эту тему. Я добавил несколько комментариев к темам, отвечая на эту ссылку на ресурсы более подробно. Вот ссылка на вопрос: stackoverflow.com/questions/547118/storing-mysql-guid-uuids - я ожидаю, что эта тема станет более распространенной, когда люди начнут рассматривать AWS и Aurora.
Зак Яннсен
Ответы:
104
Мой администратор базы данных спросил меня, когда я спросил о наилучшем способе хранения GUID для моих объектов, почему мне нужно было хранить 16 байтов, когда я мог сделать то же самое в 4 байта с целым числом. Поскольку он поставил мне этот вызов, я подумал, что сейчас самое время упомянуть об этом. Что, как говорится...
Вы можете хранить guid как двоичный файл CHAR (16), если хотите наиболее оптимально использовать пространство для хранения.
Потому что с 16 байтами вы можете генерировать вещи в разных базах данных, на разных машинах, в разное время и при этом без проблем объединять данные вместе :)
Billy ONeal
4
нужен ответ, что на самом деле является двоичным символом char 16? не чар? не бинарный? Я не вижу такого типа ни в одном из инструментов mysql gui, ни в документации на сайте mysql. @BillyONeal
nawfal
3
@nawfal: Char - это тип данных. BINARY - это спецификатор типа для типа. Единственный эффект, который он имеет, - это изменение порядка сортировки в MySQL. См. Dev.mysql.com/doc/refman/5.0/en/charset-binary-op.html для получения более подробной информации. Конечно, вы можете просто использовать тип BINARY напрямую, если ваш инструмент редактирования базы данных позволяет вам это делать. (Старые инструменты не знают о типе двоичных данных, но знают о флаге двоичного столбца)
Billy ONeal
2
поле CHAR и BINARY - это одно и то же. Если вы хотите перейти на самый базовый из уровней, CHAR - это двоичное поле, ожидающее значение от 0 до 255 с целью представления указанного значения значением, отображенным из справочной таблицы (в большинстве случаев сейчас UTF8). Поле BINARY ожидает тот же тип значения без какого-либо намерения представлять упомянутые данные из справочной таблицы. Я использовал CHAR (16) в течение дней 4.x, потому что тогда MySQL был не так хорош, как сейчас.
thaBadDawg
15
Есть несколько веских причин, по которым GUID намного лучше, чем автоинкремент. Джефф Этвуд перечисляет эти . Для меня лучшим преимуществом использования GUID является то, что моему приложению не понадобится обратное обращение к базе данных, чтобы узнать ключ сущности: я мог бы заполнить его программно, что я не смог бы сделать, если бы использовал поле автоинкремента. Это избавило меня от нескольких головных болей: с GUID я могу управлять сущностью одинаково, независимо от того, сущность уже сохранена или она совершенно новая.
@AfshinMehrabani Это просто, понятно и понятно для человека. Конечно, в этом нет необходимости, но если сохранение этих дополнительных байтов не повредит, то это лучшее решение.
user1717828
2
Хранение тире может быть не очень хорошей идеей, потому что это приведет к увеличению накладных расходов. Если вы хотите сделать его читаемым человеком, сделайте приложение читаемым с тире.
Лукка Ферри
@AfshinMehrabani еще одно соображение заключается в анализе его из базы данных. Большинство реализаций ожидают тире в действительном guid.
Райан Гейтс
Вы можете вставить дефис при извлечении, чтобы легко преобразовать символ (32) в символ (36). используйте Вставить FN mySql.
joedotnot
33
В дополнение к ответу ThaBadDawg, используйте эти удобные функции (благодаря моему более мудрому коллеге), чтобы получить строку длиной 36 обратно в массив байтов из 16.
CHAR(16)на самом деле BINARY(16), выберите предпочтительный вкус
Чтобы лучше следовать коду, возьмите пример с приведенным ниже порядковым номером GUID. (Недопустимые символы используются в иллюстративных целях - каждый из них содержит уникальный символ.) Функции преобразуют порядок байтов для достижения порядка битов для превосходной кластеризации индекса. Переупорядоченная направляющая показана под примером.
Для любопытных, эти функции превосходят просто UNHEX (REPLACE (UUID (), '-', '')), потому что он размещает биты в порядке, который будет работать лучше в кластеризованном индексе.
Slashterix
Это очень полезно, но я чувствую, что его можно улучшить с помощью источника CHARи BINARYэквивалентности ( документы, по- видимому, подразумевают, что существуют важные различия и объяснение того, почему производительность кластерного индекса лучше с переупорядоченными байтами.
Патрик М.
Когда я использую это, мой гид изменяется. Я пытался вставить его, используя как unhex (replace (string, '-', '')), так и функцию выше, и когда я конвертирую их обратно теми же методами, выбранный guid не тот, который был вставлен. Что превращает гид? Все, что я сделал, это скопировал код сверху.
vsdev
@JonathanOliver Не могли бы вы поделиться кодом для функции BinaryToGuid ()?
Арун Аванатан,
27
char (36) будет хорошим выбором. Также можно использовать функцию MySQL UUID (), которая возвращает 36-символьный текстовый формат (шестнадцатеричный с дефисами), который можно использовать для извлечения таких идентификаторов из БД.
«Лучше» зависит от того, для чего вы оптимизируете.
Насколько вы заботитесь о размере / производительности хранилища в сравнении с простотой разработки? Что еще более важно - вы генерируете достаточно GUID или загружаете их достаточно часто, чтобы это имело значение?
Если ответ «нет», char(36)это более чем достаточно, и это делает хранение / выборку GUID очень простым. В противном случае binary(16)это разумно, но вам придется опираться на MySQL и / или на предпочитаемый вами язык программирования, чтобы конвертировать туда и обратно из обычного строкового представления.
Если вы размещаете программное обеспечение (например, веб-страницу) и не продаете / не устанавливаете в клиенте, вы всегда можете начать с char (36), чтобы упростить разработку на ранней стадии, и перейти к более компактному формат по мере роста использования системы и начала нуждаться в оптимизации.
Хави Монтеро
1
Самым большим недостатком гораздо большего символа (36) является то, сколько места займет индекс. Если у вас есть большое количество записей в базе данных, вы удваиваете размер индекса.
bpeikes
8
Двоичный (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 order9ABC = middle 2 timestamp bytes in big endian
D =1to signify a version 1 UUID
EFG = most significant 12 bits of the timestamp in big endian
Когда вы преобразуете в двоичный файл, лучшим порядком для индексации будет: EFG9ABC12345678D + остальное.
Вы не хотите поменять местами 12345678 на 78563412, потому что больший порядок байтов уже дает лучший порядок байтов двоичного индекса. Однако вы хотите, чтобы наиболее значимые байты были перемещены перед младшими байтами. Следовательно, EFG идет первым, затем идут средние и младшие биты. Создайте дюжину UUID с помощью uuid () в течение минуты, и вы должны увидеть, как этот порядок дает правильный ранг.
Первые два UUID были сгенерированы ближе всего по времени. Они различаются только в последних 3 полубайтах первого блока. Это наименее значимые биты метки времени, что означает, что мы хотим сдвинуть их вправо, когда преобразуем это в индексируемый байтовый массив. В качестве встречного примера последний идентификатор является самым текущим, но алгоритм обмена KCD поместил бы его перед третьим идентификатором (3e перед dc, последние байты из первого блока).
*** обратите внимание, что я не разделяю ниппель версии с старшими 12 битами метки времени. Это D клев от вашего примера. Я просто бросаю это впереди. Так что моя двоичная последовательность заканчивается тем, что DEFG9ABC и так далее. Это означает, что все мои проиндексированные UUID начинаются с одного и того же куска. Статья делает то же самое.
Я читал эту статью раньше. Я нахожу это очень интересным, но тогда как мы должны выполнить запрос, если мы хотим фильтровать по идентификатору, который является двоичным? Я думаю, нам нужно снова проклясть, а затем применить критерии. Это так требовательно? Зачем хранить двоичный файл (16) (уверен, что он лучше, чем varchar (36)) вместо bigint из 8 байт?
Кстати, UUIDv4 полностью случайный и не требует чанкинга.
Махмуд Аль-Кудси
2
Я бы предложил использовать функции, указанные ниже, так как те, что упомянуты @ bigh_29, преобразуют мои направляющие в новые (по причинам, которые я не понимаю). Кроме того, они немного быстрее в тех тестах, которые я проводил на своих столах. https://gist.github.com/damienb/159151
если у вас есть значение char / varchar, отформатированное как стандартный GUID, вы можете просто сохранить его как BINARY (16), используя простой CAST (MyString AS BINARY16), без всех этих ошеломляющих последовательностей CONCAT + SUBSTR.
BINARY (16) поля сравниваются / сортируются / индексируются намного быстрее, чем строки, а также занимают в два раза меньше места в базе данных
Выполнение этого запроса показывает, что CAST преобразует строку uuid в байты ASCII: set @a = uuid (); выберите @a, hex (cast (@a AS BINARY (16))); Я получаю 16f20d98-9760-11e4-b981-feb7b39d48d6: 3136663230643938 2D 39373630 2D 3131 (добавлены пробелы для форматирования). 0x31 = ascii 1, 0x36 = ascii 6. Мы даже получаем 0x2D, который является дефисом. Это мало чем отличается от простого сохранения guid в виде строки, за исключением того, что вы усекаете строку до 16-го символа, что приводит к удалению части идентификатора, относящейся к конкретной машине.
bigh_29
Да, это просто усечение. select CAST("hello world, this is as long as uiid" AS BINARY(16));производитhello world, thi
Ответы:
Мой администратор базы данных спросил меня, когда я спросил о наилучшем способе хранения GUID для моих объектов, почему мне нужно было хранить 16 байтов, когда я мог сделать то же самое в 4 байта с целым числом. Поскольку он поставил мне этот вызов, я подумал, что сейчас самое время упомянуть об этом. Что, как говорится...
Вы можете хранить guid как двоичный файл CHAR (16), если хотите наиболее оптимально использовать пространство для хранения.
источник
Я бы сохранил его как символ (36).
источник
-
с.В дополнение к ответу ThaBadDawg, используйте эти удобные функции (благодаря моему более мудрому коллеге), чтобы получить строку длиной 36 обратно в массив байтов из 16.
CHAR(16)
на самом делеBINARY(16)
, выберите предпочтительный вкусЧтобы лучше следовать коду, возьмите пример с приведенным ниже порядковым номером GUID. (Недопустимые символы используются в иллюстративных целях - каждый из них содержит уникальный символ.) Функции преобразуют порядок байтов для достижения порядка битов для превосходной кластеризации индекса. Переупорядоченная направляющая показана под примером.
Черточки удалены:
источник
GuidToBinary
($ guid char (36)) RETURNS binary (16) RETURN CONCAT (UNHEX (SUBSTRING ($ guid, 7, 2))), UNHEX (SUBSTRING ($ guid, 5, 2)), UNHEX (SUBSTRING ($ guid, 3, 2)), UNHEX (SUBSTRING ($ guid, 1, 2)), UNHEX (SUBSTRING ($ guid, 12, 2)), UNHEX (SUBSTRING ($ guid, 10, 2)), UNHEX (SUBSTRING ($ guid, 17, 2)), UNHEX (SUBSTRING ($ guid, 15, 2)), UNHEX (SUBSTRING ($ guid, 20, 4))), UNHEX (SUBSTRING ($ guid, 25, 12)));CHAR
иBINARY
эквивалентности ( документы, по- видимому, подразумевают, что существуют важные различия и объяснение того, почему производительность кластерного индекса лучше с переупорядоченными байтами.char (36) будет хорошим выбором. Также можно использовать функцию MySQL UUID (), которая возвращает 36-символьный текстовый формат (шестнадцатеричный с дефисами), который можно использовать для извлечения таких идентификаторов из БД.
источник
«Лучше» зависит от того, для чего вы оптимизируете.
Насколько вы заботитесь о размере / производительности хранилища в сравнении с простотой разработки? Что еще более важно - вы генерируете достаточно GUID или загружаете их достаточно часто, чтобы это имело значение?
Если ответ «нет»,
char(36)
это более чем достаточно, и это делает хранение / выборку GUID очень простым. В противном случаеbinary(16)
это разумно, но вам придется опираться на MySQL и / или на предпочитаемый вами язык программирования, чтобы конвертировать туда и обратно из обычного строкового представления.источник
Двоичный (16) будет хорошо, лучше, чем использование varchar (32).
источник
Подпрограмма GuidToBinary, опубликованная KCD, должна быть настроена так, чтобы учитывать расположение битов временной метки в строке GUID. Если строка представляет UUID версии 1, как те, которые возвращаются подпрограммой mysql uuid (), то временные компоненты включаются в буквы 1-G, исключая D.
Когда вы преобразуете в двоичный файл, лучшим порядком для индексации будет: EFG9ABC12345678D + остальное.
Вы не хотите поменять местами 12345678 на 78563412, потому что больший порядок байтов уже дает лучший порядок байтов двоичного индекса. Однако вы хотите, чтобы наиболее значимые байты были перемещены перед младшими байтами. Следовательно, EFG идет первым, затем идут средние и младшие биты. Создайте дюжину UUID с помощью uuid () в течение минуты, и вы должны увидеть, как этот порядок дает правильный ранг.
Первые два UUID были сгенерированы ближе всего по времени. Они различаются только в последних 3 полубайтах первого блока. Это наименее значимые биты метки времени, что означает, что мы хотим сдвинуть их вправо, когда преобразуем это в индексируемый байтовый массив. В качестве встречного примера последний идентификатор является самым текущим, но алгоритм обмена KCD поместил бы его перед третьим идентификатором (3e перед dc, последние байты из первого блока).
Правильный порядок для индексации будет:
См. Эту статью для поддержки информации: http://mysql.rjweb.org/doc.php/uuid
*** обратите внимание, что я не разделяю ниппель версии с старшими 12 битами метки времени. Это D клев от вашего примера. Я просто бросаю это впереди. Так что моя двоичная последовательность заканчивается тем, что DEFG9ABC и так далее. Это означает, что все мои проиндексированные UUID начинаются с одного и того же куска. Статья делает то же самое.
источник
Для тех, кто только что наткнулся на это, теперь есть гораздо лучшая альтернатива, согласно исследованию Percona.
Он состоит из реорганизации блоков UUID для оптимальной индексации, а затем преобразования в двоичный файл для сокращения объема хранения.
Прочитайте полную статью здесь
источник
Я бы предложил использовать функции, указанные ниже, так как те, что упомянуты @ bigh_29, преобразуют мои направляющие в новые (по причинам, которые я не понимаю). Кроме того, они немного быстрее в тех тестах, которые я проводил на своих столах. https://gist.github.com/damienb/159151
источник
если у вас есть значение char / varchar, отформатированное как стандартный GUID, вы можете просто сохранить его как BINARY (16), используя простой CAST (MyString AS BINARY16), без всех этих ошеломляющих последовательностей CONCAT + SUBSTR.
BINARY (16) поля сравниваются / сортируются / индексируются намного быстрее, чем строки, а также занимают в два раза меньше места в базе данных
источник
select CAST("hello world, this is as long as uiid" AS BINARY(16));
производитhello world, thi