В очередной раз чинил наш фреш (там опять приключения с историей данных, расскажу как-нибудь при случае) и снова столкнулся с ноу-хау платформы по хранению 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; она может усиливать фрагментацию индекса и снижать производительность как сама по себе, так и виде последствий.
Если же ключи в основном возрастают, новые записи обычно добавляются в конец индекса. Страницы заполняются последовательнее, и вставки часто обходятся дешевле.
(правда, при большом числе одновременных вставок тут возникает другая проблема: все хотят записать данные в последнюю страницу индекса и начинают толкаться локтями, но это уже другая история)
Мелочь, да? Но мне нравятся подобные штуки: смотришь себе на странненькие шестнадцать байт в базе данных, а за ними, кажется, проступает вполне осмысленное архитектурное решение, принятое неизвестно кем много лет назад.