Формирует ли метод ПолучитьСсылку запрос к СУБД и как правильно искать по UUID в запросах 1С?

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

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

1. Как устроен метод ПолучитьСсылку() на уровне платформы и СУБД

Для начала проанализируем, что представляет собой объект ссылки в платформе 1С. Ссылка — это чисто программная абстракция, структура в оперативной памяти сервера приложений или клиента. На физическом уровне она состоит всего из двух ключевых элементов:

  1. Идентификатор типа метаданных (TypeID) — числовой код, определяющий, к какой таблице (например, справочнику Номенклатура или документу РеализацияТоваровУслуг) относится данный объект.
  2. Уникальный идентификатор (UUID) — 128-битное (16-байтное) двоичное число, уникальное в рамках всей информационной базы.

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

Платформе абсолютно неважно, существует ли физически строка с таким идентификатором в таблице базы данных в данный момент. Ссылка будет успешно создана в памяти. Проверить это очень просто: мы можем передать в метод абсолютно случайный, сгенерированный "из головы" UUID, и платформа мгновенно вернет нам объект ссылки.

Рассмотрим пример кода:


МойУИД = Новый УникальныйИдентификатор("1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d");
// Метод выполняется мгновенно в памяти, СУБД не задействуется
СсылкаНаНоменклатуру = Справочники.Номенклатура.ПолучитьСсылку(МойУИД);

Запрос к СУБД будет отправлен только тогда, когда мы попытаемся "разыменовать" эту ссылку — то есть обратиться к ее реквизитам через точку (например, СсылкаНаНоменклатуру.Наименование) или вызвать метод ПолучитьОбъект(). В этот момент платформа сформирует SQL-запрос типа SELECT к таблице прикладного объекта с фильтром по полю _IDRRef = &Ссылка. Если объекта с таким UUID в базе нет, СУБД вернет пустой результат, а в интерфейсе 1С мы увидим надпись "<Объект не найден...>".

2. Почему профайлер SQL иногда показывает запросы при вызове ПолучитьСсылку()

В ходе обсуждений разработчики иногда замечают, что при мониторинге активности в SQL Profiler (или технологическом журнале 1С) в момент вызова ПолучитьСсылку() фиксируются обращения к СУБД. Однако эти запросы адресуются не к таблицам прикладных объектов (справочников или документов), а к служебным таблицам базы данных (таким как Params, Config или v8users).

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

Таким образом, единичные запросы к служебным таблицам — это накладные расходы на инициализацию кэша метаданных платформы, а не следствие работы самого метода генерации ссылки.

3. Механизм генерации UUID в 1С и схожесть идентификаторов

Часто разработчики замечают, что последовательно созданные в одной сессии объекты имеют очень похожие UUID, отличающиеся буквально несколькими символами в начале, тогда как правая часть идентификатора остается полностью идентичной. Из-за этого возникает ложное предположение, что платформа делает запрос к СУБД к какому-то системному счетчику или автоинкременту, чтобы получить "следующий" свободный номер.

Проанализируем алгоритм генерации UUID. Платформа 1С:Предприятие использует международный стандарт RFC 4122 (версия 1 / Version 1, Time-Based). Этот алгоритм генерирует идентификаторы на основе двух ключевых параметров:

  1. Текущее системное время (количество 100-наносекундных интервалов, прошедших с момента перехода на Григорианский календарь).
  2. Уникальный идентификатор узла (Node ID), в качестве которого выступает физический MAC-адрес сетевой карты сервера приложений 1С.

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

Важное предупреждение о коллизиях в РИБ (распределенных базах):
Использование стандарта RFC 4122 v1 накладывает определенные риски при некорректном администрировании виртуальных машин. Если в компании развернута распределенная информационная база (РИБ), а серверы приложений в разных узлах были созданы путем «холодного» клонирования одной виртуальной машины (без изменения MAC-адреса сетевой карты), то их Node ID в генераторе UUID будут полностью совпадать. При точной синхронизации времени на этих серверах возникает риск генерации абсолютно идентичных UUID в разных узлах базы данных, что приведет к коллизиям при обмене данными. Чтобы избежать этого, всегда выполняйте процедуру sysprep и следите за уникальностью MAC-адресов сетевых плат на серверах.

4. Как правильно и производительно искать по UUID в запросах 1С

Рассмотрим практическую задачу: у нас есть массив уникальных идентификаторов в виде строк или объектов УникальныйИдентификатор, и нам необходимо найти соответствующие им элементы справочника в запросе. Существует два основных подхода к решению этой задачи.

Подход А: Предварительная генерация ссылок в коде (Рекомендуемый)

При этом подходе мы сначала преобразуем имеющиеся UUID в объекты ссылок в коде 1С, используя метод ПолучитьСсылку(), а затем передаем готовый массив ссылок в качестве параметра запроса.

Разберем этот вариант на примере кода:


// Исходный массив строковых UUID
МассивСтрокУИД = Новый Массив;
МассивСтрокУИД.Добавить("a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d");
МассивСтрокУИД.Добавить("f6e5d4c3-b2a1-0f9e-8d7c-6b5a4f3e2d1c");

// Шаг 1: Конвертируем строки в ссылки в оперативной памяти (без обращения к СУБД)
МассивСсылок = Новый Массив;
Для Каждого СтрокаУИД Из МассивСтрокУИД Цикл
    ТекущийУИД = Новый УникальныйИдентификатор(СтрокаУИД);
    СсылкаНаОбъект = Справочники.Номенклатура.ПолучитьСсылку(ТекущийУИД);
    МассивСсылок.Добавить(СсылкаНаОбъект);
КонецЦикла;

// Шаг 2: Передаем готовые ссылки в запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Ссылка,
    |	Номенклатура.Наименование КАК Наименование
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Ссылка В (&МассивСсылок)";

Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
РезультатЗапроса = Запрос.Выполнить();

Почему это максимально быстро с точки зрения СУБД?
Когда платформа транслирует этот запрос в SQL, массив ссылок преобразуется в массив 16-байтных двоичных значений BINARY(16). В SQL-запросе это превращается в конструкцию WHERE _IDRRef IN (...). Поскольку колонка _IDRRef является кластеризованным индексом (первичным ключом) таблицы прикладного объекта, СУБД выполняет операцию Index Seek (поиск по индексу). Это самый быстрый и наименее ресурсоемкий способ поиска в СУБД.

Подход Б: Использование функции УНИКАЛЬНЫЙИДЕНТИФИКАТОР() в запросе

Начиная с версии платформы 8.3.22, в языке запросов 1С появилась встроенная функция УНИКАЛЬНЫЙИДЕНТИФИКАТОР(). Некоторые разработчики предпочитают передавать в запрос исходные строки или объекты UUID, выполняя сопоставление прямо в теле запроса.

Посмотрим на пример такого запроса:


// Передаем массив строк UUID напрямую в параметры запроса
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Ссылка,
    |	Номенклатура.Наименование КАК Наименование
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Номенклатура.Ссылка) В (&МассивСтрокУИД)";

Запрос.УстановитьПараметр("МассивСтрокУИД", МассивСтрокУИД);
РезультатЗапроса = Запрос.Выполнить();

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

Когда СУБД видит конструкцию WHERE Функция(_IDRRef) IN (...), она зачастую не может сопоставить это с индексом по полю _IDRRef. Вместо быстрого точечного поиска (Index Seek) СУБД будет вынуждена применить операцию Index Scan или даже Table Scan — то есть просканировать всю таблицу справочника целиком, вычисляя функцию для каждой строки базы данных. На больших таблицах (сотни тысяч или миллионы записей) такой запрос приведет к катастрофическому падению производительности и длительным блокировкам таблиц.

Резюме и рекомендации

Подводя итог нашему анализу, зафиксируем основные правила эффективной работы с идентификаторами и ссылками в 1С:

  1. Метод ПолучитьСсылку() работает исключительно в оперативной памяти и никогда не инициирует запросов к таблицам данных СУБД для поиска или валидации существования объекта.
  2. Генерация UUID на сервере приложений происходит на основе системного времени и MAC-адреса по стандарту RFC 4122 v1 без привлечения ресурсов СУБД.
  3. При необходимости поиска объектов по списку UUID самым производительным и безопасным вариантом является их предварительная конвертация в ссылки через метод ПолучитьСсылку() в коде 1С с последующей передачей массива ссылок в параметры запроса. Это гарантирует использование первичных индексов СУБД и мгновенное выполнение поисковых запросов.
← На главную