Почему нельзя использовать «Уникальный идентификатор» как измерение регистра накопления и как правильно обойти это ограничение

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки прикладных решений на платформе «1С:Предприятие» перед программистами нередко встает задача хранения внешних GUID-идентификаторов в регистрах. Это может потребоваться для интеграции со сторонними сервисами, обмена данными между информационными базами или связывания внутренних объектов с внешними сущностями. Однако при попытке указать тип УникальныйИдентификатор в качестве измерения регистра накопления разработчик сталкивается с жестким ограничением платформы: этого типа просто нет в списке доступных.

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

В чем суть проблемы: Регистр сведений vs Регистр накопления

Прежде всего проанализируем поведение самой платформы. Если мы создаем Регистр сведений, платформа без проблем позволяет нам выбрать тип УникальныйИдентификатор для измерения. Но как только мы переходим к Регистру накопления (или регистру бухгалтерии/расчета), данный тип пропадает из списка доступных типов данных для измерений.

Для понимания причин такого поведения необходимо заглянуть под капот платформы и СУБД и оценить разницу в назначении этих объектов метаданных.

Причина 1. Механизм агрегации и расчета итогов

Основная задача любого регистра накопления — быстрое получение остатков и оборотов в разрезе его измерений. Для обеспечения высокой скорости выборки СУБД не рассчитывает остатки «на лету» по всей таблице движений. Вместо этого платформа 1С создает и поддерживает специальные таблицы итогов (агрегированные данные), которые хранят остатки на начало каждого месяца в разрезе измерений.

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

Именно поэтому разработчики платформы превентивно заблокировали возможность использовать УникальныйИдентификатор в измерениях регистров накопления.

Причина 2. Физическое хранение в СУБД и размер индексов

Рассмотрим, как данные типов СправочникСсылка и УникальныйИдентификатор хранятся на уровне СУБД (например, MS SQL Server или PostgreSQL):

Разница в 4.5 раза в объеме хранимых данных оказывает сильное негативное влияние на индексы СУБД. Индекс по строковому измерению занимает существенно больше места в оперативной памяти и на диске. Кроме того, операции сравнения бинарных данных на уровне процессора выполняются значительно быстрее, чем посимвольное сравнение строк с учетом языковых правил (Collation).

Причина 3. Фрагментация индексов (Page Splits)

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

Когда новые данные вставляются в середину существующего индекса, СУБД вынуждена выполнять операцию разбиения страниц (Page Split). Это приводит к тому, что файлы базы данных фрагментируются, производительность дисковой подсистемы падает, а время выполнения запросов увеличивается.

Платформа 1С частично решает эту проблему для стандартных ссылок с помощью механизма побайтовой перестановки (Byte Swap) при записи GUID в таблицы SQL, оптимизируя их под кластерный индекс. При использовании обычной строки в качестве измерения эта оптимизация полностью теряется.


Варианты обхода ограничения: выбираем лучшее решение

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

Вариант 1. Использование технического справочника (Рекомендуемый подход)

Это самый оптимальный и архитектурно верный способ («золотой стандарт» разработки в 1С). Вместо хранения строки или сырого GUID мы создаем специальный вспомогательный справочник-ключ.

Пошаговый алгоритм реализации:

  1. Создаем новый справочник, например, КлючиСвязиВнешнихСистем.
  2. Для минимизации размера таблиц отключаем у этого справочника использование стандартных реквизитов Код и Наименование (задаем их длину равной 0).
  3. В регистре накопления создаем измерение с типом СправочникСсылка.КлючиСвязиВнешнихСистем.
  4. При записи данных в регистр мы будем создавать элемент этого справочника, при этом в качестве его уникального идентификатора ссылки мы будем передавать наш исходный GUID.

Рассмотрим пример кода, который позволяет получить ссылку на элемент технического справочника по имеющемуся GUID без лишних запросов к базе данных:


// Функция возвращает ссылку на технический справочник по строковому представлению GUID.
// Если элемента нет в базе данных, он будет создан с указанным UUID.
Функция ПолучитьСсылкаНаКлючСвязи(СтрокаGUID) Экспорт

    УИД = Новый УникальныйИдентификатор(СтрокаGUID);
    СсылкаНаЭлемент = Справочники.КлючиСвязиВнешнихСистем.ПолучитьСсылку(УИД);
    
    // Проверим, существует ли физически элемент в базе данных
    Если СсылкаНаЭлемент.ПолучитьОбъект() = Неопределено Тогда
        // Создаем новый элемент с предопределенным уникальным идентификатором
        НовыйОбъект = Справочники.КлючиСвязиВнешнихСистем.СоздатьЭлемент();
        НовыйОбъект.УстановитьСсылкуНового(СсылкаНаЭлемент);
        НовыйОбъект.Записать();
    КонецЕсли;
    
    Возврат СсылкаНаЭлемент;

КонецФункции

Преимущества этого метода:

Вариант 2. Хранение GUID в виде строки фиксированной длины

Этот способ часто применяется в типовых конфигурациях 1С (например, в регистре СоответствиеОбъектовИнформационныхБаз). Мы объявляем измерение регистра с типом Строка, длина 36, фиксированная.

При записи данных мы преобразуем уникальный идентификатор в строку формата XML:


// Пример записи движения в регистр накопления с измерением типа Строка(36)
Движение = Движения.МойРегистрНакопления.Добавить();
Движение.Период = ТекущаяДата();
// Преобразуем объект УникальныйИдентификатор в строку фиксированной длины
Движение.ИдентификаторСтрокой = XMLСтрока(ДокументОбъект.УникальныйИдентификатор());
Движение.Сумма = 100;

Недостатки этого метода:

Использовать данный вариант стоит только в том случае, если объем записей в регистре заведомо невелик (до нескольких десятков тысяч записей), либо если регистр является регистром сведений, а не накопления.


Важное обновление платформы: Функция УникальныйИдентификатор() в запросах

Долгое время разработчики были вынуждены дублировать GUID в виде строк в измерениях регистров только ради того, чтобы иметь возможность быстро получать их текстовое представление в тяжелых запросах при интеграции (поскольку обращение через точку Ссылка.УникальныйИдентификатор в запросах выдавало ошибку).

Начиная с версии платформы 1С:Предприятие 8.3.22, эта проблема полностью решена. В язык запросов добавлена встроенная функция УникальныйИдентификатор(). Теперь вы можете получать строковый UUID любого ссылочного объекта напрямую из базы данных:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Товар,
    УникальныйИдентификатор(Номенклатура.Ссылка) КАК СтроковыйGUID
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Благодаря этому новшеству необходимость хранить строковые представления GUID в базах данных ради выгрузок во внешние системы практически сошла на нет.

Резюме

Проанализировав особенности работы платформы «1С:Предприятие» с базами данных, мы пришли к следующим выводам:

  1. Запрет на использование типа УникальныйИдентификатор в измерениях регистров накопления обусловлен заботой о производительности механизма итогов и защитой от избыточного роста индексов СУБД.
  2. Если вам критически важно использовать GUID как измерение регистра накопления, лучшим решением будет создание технического справочника без кода и наименования. Это позволит СУБД работать со сверхбыстрыми 16-байтными бинарными ключами.
  3. Использование строкового измерения длиной 36 символов допустимо, но является компромиссным вариантом, который может привести к снижению скорости проведения документов при больших объемах данных.
← На главную