UUID в базе данных 1C
17 октября 2026 ·
1С

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

Короче, UUID объектов метаданных, как и UUID обычных ссылок, хранятся в БД 1С в виде шестнадцати байт. Причём, если посмотреть на них, на UUID они вообще не похожи: например, 8e1f9db8-4be2-11ed-a101-2c4d5450919d в базе выглядит как 0xA1012C4D5450919D11ED4BE28E1F9DB8. Когда я первый раз это увидел, подумал: какой-то хэш или фокус-покус с little-endian.

На деле же платформа просто переставляет группы UUID, сохраняя порядок байтов внутри каждой:

UUID:   aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
SQL:    dddd eeeeeeeeeeee cccc bbbb aaaaaaaa

Почему так? Думаю, это попытка оптимизировать работу индексов СУБД. Дело в том, что платформа использует UUID v1 при автоматической генерации ссылок на документы, элементы справочников и другие объекты ссылочных типов. Такой UUID базируется на времени, и метка времени в нём разбита на три части. Сначала идёт её младшая часть, затем средняя и старшая:

8e1f9db8-4be2-11ed-a101-2c4d5450919d
│        │    │    │    │
│        │    │    │    └─ Node ID (48 бит)
│        │    │    └────── Clock sequence + variant (16 бит)
│        │    └─────────── Time high + version (16 бит)
│        └──────────────── Time mid (16 бит)
└───────────────────────── Time low (32 бит)

В базе 1С тот же UUID выглядит так:

0xA1012C4D5450919D11ED4BE28E1F9DB8
  │   │           │   │   │
  │   │           │   │   └─ Time low (32 бит)
  │   │           │   └───── Time mid (16 бит)
  │   │           └───────── Time high + version (16 бит)
  │   └───────────────────── Node ID (48 бит)
  └───────────────────────── Clock sequence + variant (16 бит)

Получается, после перестановки части метки времени идут от старшей к младшей, и при одинаковых clock sequence и node ID такие UUID будут строго возрастающими.

Ссылки — часть ключей индексов. Если ключи индексов приходят в случайном порядке, они попадают в разные места B-tree, и когда нужная страница индекса уже заполнена, её приходится делить: выделять новую страницу, переносить туда часть записей и обновлять ссылки в дереве. Эта операция называется page split; она может усиливать фрагментацию индекса и снижать производительность как сама по себе, так и виде последствий.

Если же ключи в основном возрастают, новые записи обычно добавляются в конец индекса. Страницы заполняются последовательнее, и вставки часто обходятся дешевле.

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

Мелочь, да? Но мне нравятся подобные штуки: смотришь себе на странненькие шестнадцать байт в базе данных, а за ними, кажется, проступает вполне осмысленное архитектурное решение, принятое неизвестно кем много лет назад.