Как формируется GUID (UUID) в 1С и почему могут совпадать идентификаторы в разных базах?

Программист IT и автоматизация бизнеса
← На главную

В процессе разработки и поддержки систем на платформе 1С специалисты часто сталкиваются с понятием GUID (Globally Unique Identifier), или Уникального Идентификатора ссылочных объектов. На первый взгляд кажется, что это абсолютно случайная строка из 36 символов, исключающая любые совпадения. Однако на практике возникают ситуации, когда объекты в разных информационных базах получают идентичные идентификаторы и перезаписывают друг друга при обмене.

Разберем подробно, на основе каких данных платформа 1С генерирует GUID, почему строковое представление отличается от бинарного хранения в СУБД, по каким причинам происходят коллизии и как разработчик может управляемо создавать идентификаторы.

Алгоритм формирования GUID и инкрементный механизм

Вопреки распространенному заблуждению, платформа 1С формирует GUID не по стандарту случайных чисел (типа UUID v4), а использует модифицированный последовательный алгоритм — SequentialUUID.

Проанализируем, как происходит генерация ссылки нового объекта в рамках пользовательского или сервисного сеанса:

  1. При старте сеанса или при вызове первого генератора платформа запрашивает у операционной системы начальное значение (задействуются системные вызовы Windows API UuidCreateSequential или Linux-функция uuid_generate_time). Этот базовый GUID опирается на текущую метку времени, системный счетчик последовательности RPC и аппаратно-системные идентификаторы оборудования.
  2. Для каждого последующего ссылочного объекта (справочника, документа, элемента плана видов характеристик и т.д.), создаваемого в рамках текущего сеанса, платформа не генерирует новый GUID «с нуля», а инкрементирует (увеличивает на 1) младшую часть стартового идентификатора.

Посмотрим на пример того, как выглядят последовательно созданные GUID в одном сеансе 1С:

Стартовый GUID: 6F9619FF-8B86-D011-B42D-00CF4FC964F0
Следующий объект: 6F9619FF-8B86-D011-B42D-00CF4FC964F1
Следующий объект: 6F9619FF-8B86-D011-B42D-00CF4FC964F2

Такой механизм обеспечивает высокую скорость создания объектов и оптимальную упаковку данных в индексах СУБД.

Особенности хранения GUID в базе данных и байтовая перестановка

Если сравнить строковое представление уникального идентификатора в коде 1С и его фактическое бинарное значение в таблицах СУБД (например, в MS SQL Server в поле типа binary(16)), можно заметить различие в порядке следования групп символов.

Рассмотрим, как платформа 1С выполняет байтовую перестановку при записи на уровень СУБД:

Строковое представление УникальныйИдентификатор в 1С:
6F9619FF-8B86-D011-B42D-00CF4FC964FF

Фактическое хранение в физической таблице СУБД:
6F9619FF-D011-8B86-B42D-00CF4FC964FF

Зачем нужна байтовая перестановка?
В СУБД MS SQL Server или PostgreSQL первичный ключ по ссылочному полю часто входит в кластерный индекс. Если бы последовательно возрастающая часть GUID находилась в самом конце бинарного значения при стандартной сортировке SQL, каждая новая запись приводила бы к случайной вставке в произвольные страницы индекса, что вызвало бы сильную фрагментацию физических файлов базы данных.
Платформа 1С меняет байты местами таким образом, чтобы инкрементируемая (часто меняющаяся) часть перемещалась в нужную позицию. В результате последовательно созданные объекты записываются в физические таблицы СУБД монотонно, предотвращая фрагментацию индексов и существенно повышая производительность операций записи.

Почему могут совпадать GUID в разных базах данных?

Теоретическая вероятность случайного совпадения двух 128-битных UUID крайне мала. Однако на практике коллизии (появление дублей GUID) встречаются довольно часто. Выясним основные причины их возникновения:

  1. Клонирование информационных баз: Если вторая база данных была создана путем физического копирования первой (файловый вариант или сдернутый бэкап СУБД), в ней уже присутствуют все существующие GUID. При дальнейшем параллельном вводе данных или синхронизации через обмены объекты с одинаковыми GUID могут затереть друг друга.
  2. Клонирование операционных систем и виртуальных машин: Системный генератор ОС использует аппаратные данные оборудования и состояния системных служб. Если администраторы клонируют образ виртуальной машины или ОС на несколько рабочих станций без сброса настроек (например, без использования утилиты Sysprep) и на этих машинах одновременно запускаются сеансы 1С, системный API генерации GUID может вернуть абсолютно одинаковые стартовые значения.
  3. Откат состояния виртуальных машин (снапшоты): При разворачивании виртуальной машины из ранее сохраненного снапшота внутренний счетчик генератора ОС откатывается назад, что при последующей генерации объектов в аналогичный миллисекундный интервал приведет к дублированию стартового GUID.

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

Как программно управлять GUID и предотвращать коллизии

В платформах 1С 8.x разработчик имеет возможность переопределить стандартный GUID до момента первичной записи объекта в базу данных. Для этого используются методы УстановитьСсылкуНового() у объекта или метод ПолучитьСсылку() у менеджера соответствующего объекта.

Рассмотрим пример генерации детерминированного GUID на основе уникального бизнес-ключа (например, при интеграции со сторонней системой):


// Пример формирования GUID на основе хэша внешнего кода
ВнешнийИдентификатор = "VENDOR_CODE_99481";

// Получаем MD5-хэш от строки (32 шестнадцатеричных символа)
Хеш = ЗашифроватьСтроку(ВнешнийИдентификатор, СпособХеширования.MD5);

// Формируем канонический формат GUID: 8-4-4-4-12
СтрGUID = Сред(Хеш, 1, 8) + "-" + 
          Сред(Хеш, 9, 4) + "-" + 
          Сред(Хеш, 13, 4) + "-" + 
          Сред(Хеш, 17, 4) + "-" + 
          Сред(Хеш, 21, 12);

НовыйGUID = Новый УникальныйИдентификатор(СтрGUID);

// Привязываем сформированный GUID к новому элементу справочника
НовыйЭлемент = Справочники.Контрагенты.СоздатьЭлемент();
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(НовыйGUID);

НовыйЭлемент.УстановитьСсылкуНового(НоваяСсылка);
НовыйЭлемент.Наименование = "Тестовый Контрагент";
НовыйЭлемент.Записать();

Проанализируем важные правила работы с GUID при программной разработке:

← На главную