Обновить
15
0

Пользователь

Отправить сообщение

Вот эти мифы, не имеющие ничего общего с действительностью:

  • Больший размер UUIDv7 (16 байт) якобы "снижает эффективность хранения". Загадочный параметр. Если имеется в виду скорость CRUD операций, то в PostgreSQL для UUIDv7 она такая же, как у автоинкремента (подтверждается бенчмарками, а не сомнительным теоретизированием). Если имеется в виду объем БД, то при использовании UUIDv7 устраняется необходимость в поле таймстемпа created_at, а также устраняется необходимость в замене ключей и, соответственно, в промежуточных таблицах при интеграции данных из нескольких источников. То есть, с использованием UUIDv7 объем БД может даже уменьшиться по сравнению с автоинкрементом

  • Якобы при использовании UUIDv7 имеется "повышенная сложность реализации, требующая поддержки со стороны библиотек и фреймворков". Это совершенно устаревшие сведения. Все ведущие СУБД и языки программирования уже реализовали встроенные функции генерации UUIDv7 (PostgreSQL и даже SQL Server, правда, без толковой документации), или имеют их в стандартных библиотеках (Python) или в самых популярных библиотеках (Golang, Rust). Для Java тоже есть, но я особо не интересовался

  • Упорядоченность на основе времени якобы раскрывает информацию о моменте создания объекта. Если неумело пользоваться, то раскрывает. Но в PostgreSQL и в Percona Server for MySQL значение таймстемпа в UUIDv7 можно сдвинуть хоть на несколько тысячелетий вперед (и до 1970 года назад)

  • Упорядоченность на основе времени якобы требует синхронизации системных часов между инстансами для сохранения корректной последовательности. Разные инстансы синхронизируется не между собой, а с мировым временем (по протоколу NTP и др.). Если инстансы находятся очень далеко друг от друга, то задержку сигнала можно компенсировать сдвигом значения таймстемпа. Если все же последовательность незначительно нарушается, то это никак не влияет на эффективность индексов и скорость работы БД

  • Якобы структура UUIDv7 менее случайна по сравнению с UUID v4, что может быть недостатком в сценариях, где критична полная непредсказуемость идентификаторов. Хакер, предсказавший значение UUIDv7 для строго по RFC 9562 реализованной функции генерации UUIDv7 (в PostgreSQL, Python, Rust и др.), получит нобелевку и золотой бюст на родине героя. Такое предсказание просто невозможно. И, кстати, таймстемп заметно уменьшает и без того нулевые шансы правильного предсказания. А использование UUIDv7, как и UUIDv4 для контроля доступа и других криптоцелей запрещено стандартом RFC 9562

  • Ключевым преимуществом UUID якобы стала независимо и гарантировано уникальная генерация идентификаторов в любой точке системы без централизованной координации. Часто можно столкнуться с ошибочными мнениями, что UUIDv7 нужны для распределенных систем, а для одного сервера лучше автоинкремент. Но генерировать UUIDv7 можно и на одном сервере, и UUIDv7 первоначально планировались именно для этого, а не для распределенных систем и генерации на клиенте (это лишь дополнительный бонус). UUIDv4 использовались для объединения данных из нескольких таблиц без необходимости замены ключей, но сильно замедляли работу БД. UUIDv7 разрабатывались с той же целью, но должны были и обеспечили скорость обработки данных как у автоинкремента

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

Остается ощущение чрезмерно избыточного количества разных типов идентификаторов в сообщении (id, message_id и log_id). Я совершенно уверен, что можно было бы обойтись только message_id (UUIDv7), а процедура разрешения конфликтов при этом была бы вообще не нужна.

Я хочу напомнить, что таймстемп в UUIDv7 - это по сути Всемирное координированное время (UTC), не зависящее от часового пояса, но только отсчитываемое не от 0 года, а от 1970 года в миллисекундах. В каких бы точках планеты не находились участники переписки, у них на часах устройства одно и то же время UTC. Поэтому не нужна никакая синхронизация часов участников - сейчас все компьютеры и телефоны синхронизированы с UTC достаточно точно для мессенджера. Максимальная погрешность в 100 миллисекунд воспринимается человеком как мгновение.

Если сообщения отсортировываются в интерфейсе по message_id (UUIDv7), то это значит, что они отсортированы по моменту отправки. Если сообщение пришло со значительной задержкой, то оно встанет в середину беседы, и его можно выделять как непрочитанное, пока пользователь не уберет его с экрана.

Насколько я понял, процедура разрешения конфликтов полагается на то же самое время UTC отправки сообщения. То есть результат (последовательность сообщений) точно такой же, как и при сортировке по message_id (UUIDv7).

А почему не используются UUIDv7 "для упорядочивания сообщений в пользовательском интерфейсе"? Они же последовательные, если генерятся одним процессом! Для Rust рекомендую Uuid::now_v7(). См. также статью разработчика этого метода.

А вот log_id - это явно лишний идентификатор.

Подкину для обсуждения свеженький (но уже 12.7k stars) формат TOON (https://github.com/toon-format/toon), созданный для экономной передачи в LLM огромного количества данных, вплоть до содержимого целой базы данных. Это сильно модифицированный гибрид YAML и CSV. Сам по себе он мне понравился для моих целей (а это вовсе не общение с LLM, а передача данных в 6NF). Он практически идеален: почти нет визуального мусора, многократно меньше строк, чем в JSON. Одним щелчком вставляется в Excel в правильные столбцы (я в качестве разделителей выбрал табы). Но спецификация огромная и при этом отрывочная и неудобная. Пока не сконвертировал вручную JSON в TOON (см. мой пример), на что ушло много времни, ничего не было понятно. Поэтому есть сомнения, что все конверторы будут работать одинаково, хотя их уже много понаделали. Конверсия из JSON в TOON, к сожалению, односторонняя, если я правильно понял. Возможно, что это поправят. Три часа назад вышла версия 1.0.0.
Статьи о нем:
Is JSON Dead? Meet TOON – The Token-Efficient Alternative for LLM Prompts
JSON vs TOON – Token-efficient data format for LLMs

Да, всё верно. Но идее монорельса с индивидуальными вагонетками уже много десятилетий, а есть всего три робких коммерческих реализации - в лондонском аэропорту Хитроу, в ОАЭ и в Южной Корее. И это не сетевой транспорт, а просто замена маршрутки. Дорого, громоздко, медленно, с низкой провозной способностью, на старых технологиях. В техническом плане проекты были довольно скучные, чтобы с меньшими трудностями получить государственные субсидии. Хорошая идея не выстрелила. Причины провала социальные. Идея слишком глобальна и ресурсоемка, чтобы кто-то рискнул вложить достаточно капиталов в ее масштабную реализацию. А MVP монорельса, транспортного средства и многоуровневой системы управления в гараже не создашь. Обычно в начале развития какой-то технологии возникает много конкурирующих проектов, и происходит отсев нежизнеспособных реализаций. Но монорельс легко не поменяешь на другой.

Придется признать, что к полномасштабной реализации этой идеи придется двигаться через эволюцию автомобильного транспорта: электрические роботакси, изолированные выделенные полосы (и эстакады) для роботакси без пересечений в одном уровне, где роботакси не будут скованы ПДД и действиями водителей и пешеходов, координация движения на выделенных полосах (подключенный транспорт). При этом проблема преодоления "последней мили" до дома по дорогам общего пользования тихой скоростью уже в основном решена - не придется топать пешком от станции монорельса. Более подробно можно прочитать здесь: https://habr.com/en/articles/871324/

Выделение полос для роботакси - не быстрый и проблемный процесс. Пока об этом вообще мало кто задумывается, а кто-то и возражает: выделенные полосы отнимут у автомобилистов, мы будем стоять в пробке, а роботакси будут проноситься мимо за ограждением со скоростью больше 200 км/ч сплошным потоком. Обидно же.

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

Кроме того, генерация UUIDv7 на стороне базы данных нужна в для обеспечения строгой монотонности идентификаторов. "Эта монотонность в течение миллисекунды нужна для поиска причин ошибок, пагинации по ключу (keyset pagination), поиска в логах, использования в БД временных рядов и т.п."

Авторы и контрибьюторы стандарта RFC 9562, котрый ввел UUIDv7, в первую очередь думали о генерации на стороне базы данных, и лишь попутно - о распределенных системах. К сожалению, в СМИ и на форумах много мифов о UUIDv7, в частности, что UUIDv7 это в основном про генерацию на клиентах. Вот статья (на английском), которая развеивает самые популярные мифы.

Спасибо за уточнение!

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

Незначительные нарушения монотонности не влияют на производительность БД.

The same example in JSON format (JSON-6NF) and JSON Schema

6NF JSON.json

JSON Schema.json

It's better to replace type with element_type to avoid conflict with JSON Schema.

The same example in JSON format (JSON-6NF):

[
  {
    "type": "ENTITY",
    "table": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY"
  },
  {
    "type": "REFERENCE",
    "table": "country_code",
    "reference_id": "01K3Y07Z94DGJWVMB0JG4YSDBV",
    "value": "US"
  },
  {
    "type": "ATTRIBUTE_OF",
    "entity_name": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY",
    "table": "bank_name",
    "value": "Bank Alpha",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "ATTRIBUTE_REF_OF",
    "entity_name": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY",
    "table": "country_code",
    "reference_id": "01K3Y07Z94DGJWVMB0JG4YSDBV",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "STRUCT_OF",
    "entity_name": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY",
    "table": "bank_address",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z",
    "columns": {
      "country_code": "01K3Y07Z94DGJWVMB0JG4YSDBV",
      "street": "123 Main St",
      "city": "New York",
      "zip": "10001"
    }
  },
  {
    "type": "ENTITY",
    "table": "account",
    "entity_id": "01K3Y0G45CP4GMGE94BYQ09DFM"
  },
  {
    "type": "ATTRIBUTE_OF",
    "entity_name": "account",
    "entity_id": "01K3Y0G45CP4GMGE94BYQ09DFM",
    "table": "account_balance",
    "value": 100000.5,
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "ATTRIBUTE_OF",
    "entity_name": "account",
    "entity_id": "01K3Y0G45CP4GMGE94BYQ09DFM",
    "table": "account_expiration",
    "value": "2025-12-31T23:59:59Z",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "RELATIONSHIP",
    "table": "bank_x_account",
    "relationship_id": "01K3Y0NR1Q3KTA9A6J9KYPK6YB",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z",
    "columns": {
      "bank": "01K3Y0690AJCRFEJ2J49X6ZECY",
      "account": "01K3Y0G45CP4GMGE94BYQ09DFM"
    }
  }
]

Бэкенд - это процесс.

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

Иногда бывает нужен и строгий порядок: для поиска причин багов, для пагинации. Какие-то еще были причины, сейчас не вспомню. Субмиллисекундная часть нужна именно для строгого порядка, но при генерации на клиенте его не удастся обеспечить

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

Стандартом RFC 9562 определено другое назначение поля variant. Кроме того, стандарт вообще запрещает парсинг UUID без крайней необходимости, в том числе извлечение таймстемпа. И для этого есть очень веские причины, указанные в стандарте. Я бы вообще запретил использовать небезопасную функцию uuid_extract_timestamp ( uuid ) в промышленном программном коде. Для аналитики, поиска багов и т.п. - другое дело.

Поправка: RFC 9562 разрешает парсинг UUIDv7 при крайней необходимости.

Этого не сделали исходя из принципа единственной ответственности. UUIDv7 минималистичен. Только ключ, и ничего более.

Есть и более практические соображения. Могут быть две таблицы, например, условно копии в разных схемах, в которых одни и те же UUIDv7 будут первичным ключом. Как понять, к какой из двух таблиц относится "подвисший в воздухе id"?

Тем не менее, есть два способа решения проблемы "подвисшего в воздухе id". Первый - отдельная таблица соответствия UUIDv7 имеющимся таблицам.

Второй способ - использование длинного идентификатора (например 160 бит), в старших разрядах которого будет UUIDv7, а в младших - ключ на таблицу метаданных (имя таблицы "подвисшего в воздухе id" и др.) и опционально контрольная сумма. Длинные идентификаторы, содержащие UUID, прямо предусмотрены стандартом RFC 9562. Но во втором способе придется хранить такие идентификаторы как строки, а не как бинарный тип UUID, что замедлит работу БД. К сожалению, в PostgreSQL нет типа данных "длинный UUID", а далекие от системного анализа разработчики считают, что и 128 бит - слишком много.

1
23 ...

Информация

В рейтинге
6 328-й
Зарегистрирован
Активность

Специализация

Системный аналитик
Ведущий
Английский язык
SQL
Базы данных
REST
XML
DWH
ETL
Greenplum
Microsoft Access
Python