При оптимизации высоконагруженных алгоритмов и обработке больших массивов данных разработчики часто сталкиваются с вопросом: обращается ли платформа к СУБД при вызове метода УникальныйИдентификатор() у ссылочного типа? Проанализируем внутреннее устройство ссылочных типов в платформе 1С:Предприятие, выясним поведение клиент-серверного взаимодействия и рассмотрим наиболее эффективные способы работы с GUID при сопоставлении данных.
Рассмотрим, как устроена ссылка в платформе 1С. Любая ссылка (например, СправочникСсылка, ДокументСсылка и т. д.) представляет собой составную структуру в памяти, состоящую из идентификатора таблицы метаданных и 16-байтного двоистого значения GUID (уникального идентификатора записи).
Когда мы вызываем метод Ссылка.УникальныйИдентификатор(), платформа не выполняет никаких запросов к базе данных. Извлечение значения происходит исключительно в оперативной памяти текущего сеанса. Более того, доступность этого метода охватывает тонкий клиент, веб-клиент, мобильные клиенты и сервер. Это означает, что если ссылка уже передана на клиент, вызов УникальныйИдентификатор() на клиенте даже не инициирует сетевой вызов к серверу 1С — GUID считывается из локального контекста ссылки в памяти клиентского приложения.
Разберем опасную конструкцию, с которой нередко можно столкнуться в коде конфигураций и внешних обработок:
// Неправильный подход, создающий критическую нагрузку на СУБД:
ГУИД = Ссылка.ПолучитьОбъект().УникальныйИдентификатор();
Проанализируем, к чему приводит такой вызов. Метод ПолучитьОбъект() выполняет полноценное считывание данных записи из таблицы СУБД, включая все реквизиты шапки и строки всех табличных частей. Если выполнять такой код в цикле по массиву или таблице ссылок, производительность упадет в сотни раз из-за избыточных дисковых и сетевых операций базы данных.
Всегда обращаемся к методу напрямую от ссылки:
// Правильный подход: выполняется мгновенно без запросов к СУБД
ГУИД = Ссылка.УникальныйИдентификатор();
Часто уникальный идентификатор требуется не в виде объекта типа УникальныйИдентификатор, а в виде стандартной строки из 36 символов (например, для обмена данными или сравнения с внешними таблицами). Классический вариант преобразования выглядит следующим образом:
СтрокаГУИД = Строка(Ссылка.УникальныйИдентификатор());
Однако в платформе предусмотрен более производительный механизм — системная функция XMLСтрока(). Посмотрим, как ее использовать:
СтрокаГУИД = XMLСтрока(Ссылка);
Вызов XMLСтрока(Ссылка) работает быстрее цепочки со Строка(), поскольку платформа сразу возвращает каноническую строку сериализации ссылки (ее GUID), минуя этап создания промежуточного объекта типа УникальныйИдентификатор в управляемой куче памяти.
Разберем практическую задачу, описанную в теме: у нас есть набор ссылок в одной таблице и строковые представления идентификаторов в другой, и их необходимо быстро сопоставить. Рассмотрим два наиболее производительных способа реализации.
Метод менеджера объекта ПолучитьСсылку() принимает объект УникальныйИдентификатор и возвращает ссылку в памяти. При этом он также не делает запросов к базе данных и не проверяет физическое наличие записи в таблице. Мы можем восстановить ссылки для второй таблицы и выполнить пакетное соединение в запросе по индексированному полю ссылки:
ТаблицаСГУИД.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Для Каждого Стр Из ТаблицаСГУИД Цикл
УИД = Новый УникальныйИдентификатор(Стр.СтрокаГУИД);
Стр.Ссылка = Справочники.Номенклатура.ПолучитьСсылку(УИД);
КонецЦикла;
// Теперь обе таблицы можно передать в Запрос и связать через ВНУТРЕННЕЕ СОЕДИНЕНИЕ по полю Ссылка
Начиная с версии платформы 8.3.22, в языке запросов 1С появилась встроенная функция УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Ссылка). Она позволяет извлекать идентификатор непосредственно в запросе. Однако обратим внимание: функция возвращает не строку, а значение типа УникальныйИдентификатор. Поэтому во входящей таблице колонка со значениями должна быть предварительно типизирована соответствующим образом:
// В таблице значений типизируем колонку как УникальныйИдентификатор
ТаблицаСГУИД.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("УникальныйИдентификатор"));
Для Каждого Стр Из ТаблицаСГУИД Цикл
Стр.Идентификатор = Новый УникальныйИдентификатор(Стр.СтрокаГУИД);
КонецЦикла;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| Т1.Ссылка КАК Ссылка,
| УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Т1.Ссылка) КАК УИД
|ПОМЕСТИТЬ ВТ_Ссылки
|ИЗ
| &ТаблицаСсылок КАК Т1
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Т1.Ссылка КАК Ссылка,
| Т2.Идентификатор КАК Идентификатор
|ИЗ
| ВТ_Ссылки КАК Т1
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТаблицаСГУИД КАК Т2
| ПО Т1.УИД = Т2.Идентификатор";
Таким образом, операция получения уникального идентификатора из ссылки является безопасной с точки зрения производительности СУБД, так как выполняется целиком в оперативной памяти без дополнительных обращений к серверу баз данных.