Pull to refresh

Comments 41

Можно смело смешивать UUIDv7 с UUID любых старых и новых версий в одном столбце/поле, предварительно отключив или изменив контроль версий, как в этом случае: https://youtrack.jetbrains.com/issue/DBE-18094/SQL-column-display-type-auto-detection-doesnt-work-for-UUIDv7

Ну как смело. Работать это будет, но что по сути происходит. Весь этот UUIDv7 сделан для того, чтобы таблица росла по возможности всегда с конца. Тогда не приходится раздвигать записи. Если смешивать разные UUID, тогда снова начинаем раздвигать записи.

Я не предлагаю делать новые записи с устаревшими UUIDv1-5. Но в таблицу с имеющимися записями с UUIDv1-5 можно добавлять записи с UUIDv7. Благодаря тому, что записи в БД хранятся не сплошным массивом, а в 8-килобайтных станицах, а страницы заполнены не полностью, не придется раздвигать имеющиеся записи (точнее, перезаписывать индексы) при вставке новых записей. Свободное пространство на странице используется для размещения новых записей или обновления существующих без необходимости перераспределения данных на других страницах. Это решение позволяет не переделывать старые ключи в формате UUIDv1-5 на новые в формате UUIDv7, что очень обременительно. И при этом не будет никаких нежелательных последствий.

Очень странно, что вы пишете про UUIDv1-5. Я думаю, большинство не знало ни о чём, кроме UUIDv4.

А UUIDv3 и UUIDv5 суть MD5 и SHA-1 от строки, посоленной UUID пространства имён, и их смысл в том, чтобы повторяемо преобразовывать одну и ту же строку в один и тот же UUID. Например, параметризованные интерфейсы Windows Runtime обладают PIID, который по традиции может быть UUIDv4, а специализации интерфейсов имеют IID, вычисленный как UUIDv5 от специально составленных машинных строк с участием PIID и закодированных типов-параметров. Ну и ещё там участвует, конечно, пространство имён специализированных интерфейсов. Это я всё расписал к тому, что в Windows Runtime понятно, как и зачем повторяемо вычислять UUIDv5, а в базе данных применять UUIDv5 почти то же самое, что применять строку в качестве первичного ключа, но если у вас на примете есть строка, подходящая на роль первичного ключа, то почему бы не взять её напрямую.

В UUIDv4 первые шесть байтов заполнены случайно. В UUIDv7 первые шесть байтов заполнены 48-битным временем в миллисекундах с потенциально каким-то смещением. Можно от эпохи Юникс, но стандарт допускает смещение, и тогда это просто какое-то миллисекундное время. Среди прошлых UUIDv4 случайные значения как-то по Пуассону заполнили диапазон, а когда мы начинаем подмешивать UUIDv7, то они интенсивно заполняют очень узкую полосу значений, и всё, что оказалось правее, становится практически вечными кандидатами на смещение. Если не сдвигать время, справа оказывается чуть менее, чем всё.

Устаревшим можно считать UUIDv1, заменённый на UUIDv6 с единственным отличием в порядке байт, чтобы сделать UUIDv1 лексикографически возрастающими со временем. Кто хотел лексикографическое возрастание, вряд ли бы взял UUIDv1, в котором этого свойства не было.

Устаревшим можно считать UUIDv3 (MD5), так как есть UUIDv5 (SHA-1), но если где-то уже принято использование UUIDv3, то от него не представляется возможным отказаться. А UUIDv5 не устарел, замены-то ему нет. Но в базе данных ни то, ни другое вряд ли встретишь из-за их антисуррогатной природы, а на месте UUID в базе данных обычно ожидаются суррогатные ключи. И UUIDv4 не устарел, другое дело, что мы можем больше не хотеть писать UUIDv4 именно в базу данных.

Устаревшим можно считать ULID, с которого и начался сыр-бор с отказом от UUIDv4. У ULID нет номера. Ну или номером ULID можно считать UUIDv7, который его стандартизирует.

Нельзя однозначно считать устаревшим UUIDv6, который просто поменял порядок байт UUIDv1, и больше ни на какую новизну не претендовал. Я так понял, кому-то очень полезно, что в UUID штампуется идентификатор узла, и они осознанно применяют UUIDv6, а не UUIDv7.

Если не использовать сдвиг времени, то ULID, UUIDv6 и UUIDv7 совместимы внутри одной таблицы.

"Очень странно, что вы пишете про UUIDv1-5... в базе данных применять UUIDv5 почти то же самое, что применять строку в качестве первичного ключа, но если у вас на примете есть строка, подходящая на роль первичного ключа, то почему бы не взять её напрямую" =>

Да есть разработчики, которые упорно тащат UUIDv5 в БД, так как у них в источнике данных строка, а в БД у них уже UUID ("исторически так сложилось"). После долгих препирательств с ними пришлось вставить в RFC 9562 рекомендацию против таких ненадежных костылей: "Designers of database schema are cautioned against using name-based UUIDs (see Sections 5.3 and 5.5) as primary keys in tables. ... The general advice is to avoid name-based UUID natural keys and, instead, to utilize time-based UUID surrogate keys...".

________________________

"когда мы начинаем подмешивать UUIDv7, то они интенсивно заполняют очень узкую полосу значений, и всё, что оказалось правее, становится практически вечными кандидатами на смещение " =>

Да, есть такая проблема, но она успешно решается в современных СУБД. Например, B-Tree индексы в PostgreSQL спроектированы для эффективной работы с упорядоченными данными. Они автоматически управляют распределением данных по страницам и перебалансировкой дерева при необходимости (например, при операциях разделения страниц).

________________________

"Если не использовать сдвиг времени, то ULID, UUIDv6 и UUIDv7 совместимы внутри одной таблицы" =>
В PostgreSQL и в ClickHouse для хранения UUID любых версий используется один и тот же тип данных. Таким образом, внутри одной таблицы совместимы UUID любых версий, причем независимо от того, есть ли сдвиг времени таймстемпа.

в базе данных применять UUIDv5

Вам же написали

в базе данных ни то, ни другое вряд ли встретишь

Уже, наверное, в десятый раз Вам пишу. Использование UUID не ограничивается базами данных. И источником UUID тоже не обязательно выступает база данных. UUID даже STM32 или ESP2866/32 могут генерировать.

Разговор в данном случае идет об использовании именно в БД. Ваш комментарий неуместен.

Да есть разработчики, которые упорно тащат UUIDv5 в БД, так как у них в источнике данных строка, а в БД у них уже UUID ("исторически так сложилось").

О, даже так. Ну, я в шоке с них.

Просто если не самый новый Постгрес брать, там ничего встроенного, кроме UUIDv4, не было. И если Delphi взять, там ничего, кроме UUIDv4, из коробки нет. И так типично повсюду. Это надо специально заморочиться, чтобы какой-то другой UUID появился, ну вот я и подумал, что тот, кто заморочился, отдаёт себе отчёт, что делает. Когда я заморачивался с UUIDv5 в Delphi, я отдавал себе отчёт.

внутри одной таблицы совместимы UUID любых версий

Имелась в виду не принципиальная возможность набить как в бочку селёдки, а только дружественная к производительности.

Да, есть такая проблема, но она успешно решается в современных СУБД.

Ну, если она и правда так успешно решается, то нет применения v7, когда есть v4, а кто-то изобретательный ещё любит v5 в первичных ключах.

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

Как философский подход это рассуждение часто бывает правильным. Если что-то сделали, то наверное, это для чего-то было нужно? Каждой задаче - свой подходящий инструмент. Да, но только не в данном конкретном случае. Новые версии UUID появились не потому, что появились какие-то новые сценарии использования, для которых старые версии UUID не подходили. Всё гораздо прозаичнее: старые версии UUID были ужасны практически во всех сценариях использования, кроме самых примитивных и нетребовательных. Прежний стандарт - это просто сборник очевидных ошибок и просчетов. На протяжении всего срока его существования созданы и используются десятки кастомных идентификаторов, призванные устранить эти недостатки. Новый стандарт - это не дополнение старого стандарта новыми версиями UUID. Новый стандарт написан с чистого листа. В нем нет ни одного слова от старого стандарта, а старые версии UUID были сохранены лишь для того, чтобы информационные системы со старыми версиями UUID не выпали из легального поля. У разработчиков нового стандарта было огромное желание объявить устаревшими все прежние версии UUID, кроме четвертой (для специальных случаев, когда монотонность вообще не важна). Но это привело бы к большой задержке с принятием нового стандарта. Поэтому старые версии сохранили для легаси систем. Тем не менее, я рекомендую и для легаси систем по возможности переходить на седьмую версию UUID, поскольку все версии UUID совместимы между собой (если нет специального контроля версий).

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

Профилирование
#include <stdio.h>
#include <time.h>
#include <uuid/uuid.h>

void main(void) {
  uuid_t binuuid;
  struct timespec spec_start;
  struct timespec spec_end;

  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec_start);
  for (int i=0; i<1000000; i++) {
    uuid_generate_time(binuuid);
  }
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec_end);
  printf("UUIDv1: %f\n",
   (double) (spec_end.tv_nsec-spec_start.tv_nsec)/100000000+
     (double) (spec_end.tv_sec-spec_start.tv_sec) );

  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec_start);
  for (int i=0; i<1000000; i++) {
    uuid_generate_random(binuuid);
  }
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec_end);
  printf("UUIDv4: %f\n",
   (double) (spec_end.tv_nsec-spec_start.tv_nsec)/100000000+
     (double) (spec_end.tv_sec-spec_start.tv_sec) );
}

UUIDv1: 0.522976
UUIDv4: 7.314527

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

P.S. Не собираюсь защищать только вторую и третью версию. Первая/шестая, четвертая и пятая имеют свои конкретные области применения.

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

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

"Privacy and network security issues arise from using a MAC address in the node field of UUID version 1. Exposed MAC addresses can be used as an attack surface to locate network interfaces and reveal various other information about such machines (minimally manufacturer, potentially other details). Additionally, with the advent of virtual machines and containers, MAC address uniqueness is no longer guaranteed." https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html#name-update-motivation

"MAC addresses pose inherent security risks around privacy and SHOULD NOT be used within a UUID." https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html#name-security-considerations

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

Про пятую версию в стандарте тоже написано не очень лестно: "Designers of database schema are cautioned against using name-based UUIDs (Section 5.3/Section 5.5) as primary keys in tables. A common issue observed in database schema design is the assumption that a particular value will never change, which then later turns out to be an incorrect assumption. Postal codes, license or other identification numbers, and numerous other such identifiers seem unique and unchanging at a given point time; only to later turn out to have edge cases where they need to change. The subsequent change of the identifier, used as a "name" input for name-based UUIDs, can invalidate a given database structure. In such scenarios it is observed that using any non-name-based UUID version would have resulted in the field in question being placed somewhere that would have been easier to adapt to such changes (primary key excluded from this statement). The general advice is to avoid name-based UUID natural keys and instead utilize time-based UUID surrogate keys based on the aforementioned problems detailed in this section". https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html#name-dbms-and-database-considera

А вообще я бы посоветовал изучить стандарт. В самом стандарте есть ответы практически на все возникающие вопросы.

Время генерации UUID в данном случае не интересно

Если Вам не интересно в неуказанном "данном случае", то это не значит, что это не интересно, например, в области промышленной автоматики.

интересно время вставки записи в большую таблицу

С чего Вы взяли, что UUID, например, от сотен концентраторов, в БД станут попадать в последовательности их генерации во времени, а не в последовательности их поступления от концентраторов?

И тем более, если эти данные попадают в ту же Кассандру или Кафку, которой на монотонность ключей вообще наплевать, так как шардируются данные все равно по md5 ключа.

Первая версия UUID не монотонная

Это зависит от CPU (big-endian или little-endian) и способа хранения UUID (byte string, int32, int64 или даже int128). На тех же System Z/I первая версия монотонная, даже не смотря на несколько кривое расположение clock_seq. И не всегда эта монотонность нужна - см. выше.

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

Ну хотя бы признали ограниченность собственных знаний. Уже что-то.

Для того, чтобы не тащить везде второе поле с идентификатором хоста. Особенно, если сообщения от датчиков 256 бит и UUID в них уже половину занимают.

Наоборот, такое "знание" расценивают как угрозу информационной безопасности и уникальности сгенерированных UUID

Только в случае, если этот UUID вообще может выйти за пределы системы. Есть совершенно разные сценарии использования UUID.

as primary keys in tables

Вы так же не понимаете, для чего существует V5. К БД он имеет только то отношение, что 128 битное целое не все БД, приложения, протоколы или языки программирования поддерживают, в отличии от UUID. Это просто удобный способ хеширования для случаев, когда 64-битного целого мало.

Складывается ощущение, что кроме локальной генерации UUID в качестве первичного ключа при вставке в таблицу не распределенной БД, Вы не представляете вообще, для чего UUID применяется.

По доброму прошу. Прекращайте демагогию. В Ваших сообщениях её ключевые признаки так и прут. То "очевидно", то "всем интересно", то, наоборот, "[всем] не интересно".

А от подхода, "мне плевать на деградацию производительности на порядок" - я вообще в шоке.

Вы используете UUID не по назначению - отсюда все проблемы. Хотел Вам посоветовать быструю реализацию, но не буду - Вам нужно меньше грубить людям

Вот уж точно не Вам решать, какое назначение у UUID.

Например, допустимо ли его использование для идентификации объектов таким образом, чтобы их URL/FQDN/OID или DN невозможно было восстановить из этого идентификатора.

RFC стандартизирует исключительно форматы передачи UUID по сети. Все остальное его не касается.

длительность вставки записи в большую таблицу, которая очень сильно зависит от монотонности

Проверил на PostgreSQL и pg_uuidv7. Даже на одном ядре с запрещенным параллелизмом он успевает генерировать и записывать в таблицу свыше 300 UUIDv7 за одну миллисекунду:

Function Scan on generate_series g (cost=0.00..12500.00 rows=1000000 width=16) (actual time=75.188..3108.758 rows=1000000 loops=1)

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

Тогда как монотонность между страницами БД никому не интересна.

К сожалению, если монотонность действительно необходима для оптимизации индексации в БД, то либо возвращаемся к UUIDv1/v6 (в зависимости от архитектуры), либо ждем UUIDv8 и возвращаемся к времени с дискретностью 100 нс.

Соглашусь. Автор фразы написал о длительности вставки записи с UUID в таблицу, но я бы исправил: вставка записи с индексируемым полем UUID, особенно если это база SQL Server и поле - ключ с кластерным индексом. Для чего, собственно, после страданий MS и придумала sequential uuid - монотонные гуиды

Я бы добавил: вставка записи с первичным ключом UUID

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

Стандарт разрешает использовать UUIDv7 в качестве левого сегмента ключа.

Эээ... Что это значит? Кто такой ключ и с какой стороны у него лево?

Автор, судя по его комментариям выше, не отдает себе отчета, что UUID используется и генерируется далеко не только в СУБД. Даже не смотря на то, RFC стандартизируют исключительно протоколы сетевого обмена, а вовсе не способы локального хранения и обработки данных.

Он даже не учитывает, что на разных архитектурах слева могут быть как младшие, так и старшие разряды слова. И слова могут иметь длину до 512 бит.

Ну кстати да, в сетевых протоколах как правило вначале идут старшие байты.

Это математическое надругательство установилось вследствии того что началом текста большая часть мира считает лево, тогда как младшие разряды числа все пишут справа. Рядовому гражданину трудно оценить, на сколько текст и разрядная запись чисел, это конкурирующие противоречащие друг-другу системы. По этой причине CRC в этих самых протоколах вечно выбивается тем что перевернут, ведь он математически устроен так, что имеет определенное значение на любой позиции в данных со сдвигом вплоть до бита. И потому существует аж 4 способа его реализации по направлениям (как минимум 3 из которых активно встречаются) Очень многие разработчики и тем более техписы из-за этого забивают трактовать в документациях его значение верно, если оно отличается от BigEndian, а просто записывают его в BigEndian (из-за чего даже готовые либы по их генерации не обеспечивают интеграции без погружения в детали)

Вообще много работаю с протоколами последнее время... и я то уже собаку съел, но иногда начинает казаться, что самым простым способом это фундаментально систематизировать было бы использовать уже везде LSB (согласующийся с математикой) а HEX редакторы просто выполнить "по-арабски", развернув в них отображение байт справа-налево (т.е. так как математически записываются разряды чисел),

в протоколах редко важно в какую сторону физически хранить, а если и оказывается, - то чаще в согласующуюся с математикой (длинная арифметика например вся не только лучше смотрится в LSB, но и считается быстрее). Так строки и LSB числа окажутся развернуты в привычный для чтения порядок.
Да и с диагностированием перевернутой строки в случае низкоуровневого логгера проблем особых не возникает. В отличии от развернутых кодов.

Кто-то кстати видел готовые редакторы с такой функцией типа выводить HEX по-арабски???

Кстати если бы в графических буферах перевернули X (а, что Y же перевернут и ни кто не возмущается), то вместе с перевернутым Y *внезапно* получился бы полный аффинный поворот на 180гр (что тоже имеет плюсы исключения лишних вычислений уже для геометрии - а еще физически на специализированных устройствах типа цифровых осциллографов можно было бы просто устанавливать LCD с поворотом на 180)

"DBMS vendors are encouraged to provide functionality to generate and store UUID formats defined by this specification for use as identifiers or left parts of identifiers such as, but not limited to, primary keys, surrogate keys for temporal databases, foreign keys included in polymorphic relationships, and keys for key-value pairs in JSON columns and key-value databases" https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html#name-dbms-and-database-considera

Я тут тоже могу написать "рекомендуется то-то и то-то". Какое нормативное отношение имеют рекомендации IETF к поставщикам СУБД? И тем более, какое право IETF имеет запрещать использовать AVX, в которой младшая часть в памяти и на диске слева, для эффективных манипуляций с UUID?

Покопался. ISO/IEC 9834-8:2014 явно рекомендует сохранять UUID в виде целого:

A UUID can be represented as a single integer value. To obtain the single integer value of the UUID, the 16 octets of the binary representation shall be treated as an unsigned integer encoding with the most significant bit of the integer encoding as the most significant bit (bit 7) of the first of the sixteen octets (octet 15) and the least significant bit as the least significant bit (bit 0) of the last of the sixteen octets (octet 0).

Никакими "левыми" или "правыми" частями тут и не пахнет. Фигурируют только более и менее значащие биты.

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

Но парадокс в том, что я регулярно периодически встречаю людей которые путаются в понятиях младший/старший значащий разряд...

Еще некоторых вгоняет в ступор попытка объяснить что неважно в какой (двоично ли) системе счисления компьютер считает... как для программиста тебе по сути для АЛУ доступны не двоичные разряды а как минимум 256-тичные... И потому НИКТО не в праве для тебя запретить отображать и интерпретировать логически эти значения в любой удобной для твоего алгоритма системе счисления... (математика от того не поменяется ни для каких операций)
- например я знаю несколько случаев когда 4-ичная 8-ичная или 256-тичная помогают сделать объяснение алгоритма прозрачным. А иногда даже 15-тичную 17-тичную можно юзнуть (для очень черных колдунств)
прим: делим HEX по модулю на %15= получаем сумму (по модулю) всех HEX разрядов... и прикол в том что этот трюк для десятичной знает каждая вторая домохозяйка, которая детям первоклашкам помогает с домашкой - когда проверяем делимость на 9 сложением разрядов (но в алгоритмах важно не ставить себе рамок там где их нет - трюк имеет природу и при ее понимании применим разнообразно)

Насколько понимаю, имеется в виду "составной индекс" в SQL.

Когда несколько столбцов таблицы, явно перечисленных, назначаются единой логической сущностью.

Ну например, номер телефона состоит из кода страны, кода города внутри страны, и номера абонента внутри города. Вполне можно положить как три столбца. Но чтобы обеспечить уникальность, эти три столбца надо рассматривать как одно логическое целое.

При этом порядок столбцов в объявлении ключа/индекса не обязан совпадать с порядком столбцов в объявлении таблицы. А уж в каком порядке сервер БД положит столбцы на диск, и вообще будет ли он хранить таблицу построено или постолбцово - это теоретически вообще чёрный ящик.

Соответственно "левая часть ключа" - это просто первый столбец в объявлении ключа/индекса. А как оно физически хранится при этом никого не волнует.

Это предположение неверно. Речь идет об идентификаторе (в тексте стандарта слово identifiers) - о единой строке символов, содержащейся в одном столбце/поле таблицы базы данных. Первоначально авторы стандарта обсуждали идеи UUID длиной 160 битов или переменной длины, чтобы можно было добавить в UUID идентификатор секции и иные метаданные, а также контрольную сумму. Но потом от этого отказались по соображениям совместимости. Поэтому решили, что длина UUID останется 128 битов, но в одно (текстовое или бинарное) поле таблицы БД можно поместить не только UUID, но и метаданные (ID секции, модуля, таблицы, источника, операции, сообщения и т.п.), и контрольную сумму. При этом сам UUID должен быть максимально "непрозрачным", без возможности извлекать из него какие-то бизнес-данные (дата и время, хост и т.д.). Однако UUID должен быть в левой части поля, чтобы поля были упорядочены по дате и времени создания UUID. Текст стандарта сформулирован, конечно, не очень хорошо, так как это результат компромисса.

Кстати, ключ в JSON, о котором упоминается в стандарте, не может быть составным. Это тоже опровергает Ваше предположение:

"DBMS vendors are encouraged to provide functionality to generate and store UUID formats defined by this specification for use as identifiers or left parts of identifiers such as, but not limited to, primary keys, surrogate keys for temporal databases, foreign keys included in polymorphic relationships, and keys for key-value pairs in JSON columns and key-value databases" https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html#name-dbms-and-database-considera

Как раз наоборот

left parts of identifiers such as, but not limited to, primary keys

Речь явно идёт о составном (из нескольких столбцов) PK

Этот абзац стандарта писал я сам. И я очень хорошо помню, что я имел в виду, а именно, один столбец. Жаль, что формулировка в статье вызвала неоднозначные толкования: при удалении слова "идентификатор" (осталось только "ключ") потерялась часть смысла. Теперь я поправил формулировку в статье. Но ничто в соответствующем абзаце в стандарте не указывает, что упомянутый ключ должен быть составным (так как не бывает составных идентификаторов). Да, сами по себе PK очень часто составные. Но те PK, которые являются идентификаторами, не являются составными. Идентификатор по общепринятому определению - это имя, наименование: may be a word, number, letter, symbol, or any combination of those, а не составная структура данных из нескольких полей таблицы. Если бы речь шла о нескольких полях, то это вообще не имело бы смысла упоминать в стандарте, так как и без того разработчики хранят метаданные в отдельных технических полях, а не в поле UUID.

Кстати, наверное, ни у кого не вызовет вопросов формулировка в стандарте "левая часть идентификатора"?

Не будем же притворяться. "лево" - это на 180 градусов от "право".

Особенности хорошей реализации UUIDv7:

  • Binary, including UUID type

  • Timestamp offset

  • Incremented timestamp on overflow

  • Short counter segment initialized to 0 (the most significant, leftmost bit)

  • Long enough counter segment initialized with random data

  • Global counter or microsecond precision

  • Can generate the same UUIDs at function calls

ULID не корректно сортируется на MS SQL SERVER.
ULID предполагает сортировку слева на право (левая сторона дата)
Если вы создатите таблицу с uniqueidentifier и DateTime, а затем вставите в нее данные в хронологическом порядке (ULID и дата созданные в одно время)
То вы увидите что даты идут в случайном порядке.
Также мои тесты с бенчмарком показали что время вставки имеет большой разброс от 2 до 22 секунд на вставку 100_000 строк.
Если вы будете конвертировать ваш ULID в string => nvarchar(26) то он будет сортироватся корректно.

Sign up to leave a comment.

Articles