При работе с регистрами накопления или сведений в платформе 1С часто возникает задача получить реквизиты документов-регистраторов. Если поле Регистратор имеет составной тип, включающий сотни видов документов (например, более 256), прямое обращение к реквизиту «через точку» вида Регистратор.Реквизит1 вызывает существенную проблему.
В этой статье мы подробно проанализируем причины этой проблемы и разберем практические способы ее решения в запросах 1С и коде встроенного языка.
Рассмотрим механизм работы платформа 1С при обращении к реквизитам составного типа. Когда в тексте запроса выполняется обращение Регистратор.Реквизит1, транслятор запросов 1С автоматически генерирует в SQL-запросе левое соединение (LEFT OUTER JOIN) со всеми таблицами документов, входящими в этот составной тип.
Если в составной тип входит более 256 различных документов, запрос сталкивается с жесткими ограничениями некоторых СУБД (например, устаревших версий MS SQL Server) или вызывает падение производительности и аварийное завершение работы компилятора запросов из-за слишком громоздкого плана выполнения.
Важно учитывать, что простое условие ГДЕ ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(...) или ГДЕ Регистратор ССЫЛКА ... без явного приведения типов не предотвратит создание левых соединений со всеми таблицами на этапе построения SQL-запроса.
Разберем первый способ решения задачи прямо в запросе. Для того чтобы платформе не пришлось выполнять соединения со всеми возможными таблицами, мы можем принудительно указать конкретные типы документов с помощью функции ВЫРАЗИТЬ.
Посмотрим на пример конструкции условия с ограничением типа:
ГДЕ
ВЫРАЗИТЬ(РН.Регистратор КАК Документ.РеализацияТоваровУслуг).Реквизит1 = &Значение
ИЛИ ВЫРАЗИТЬ(РН.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Реквизит1 = &Значение
При таком подходе транслятор запросов построит левые соединения только с теми таблицами документов, которые явно указаны в конструкции ВЫРАЗИТЬ, исключив все остальные виды документов из итогового SQL-запроса.
Если видов документов с нужным реквизитом много, но их список известен заранее или может быть получен через метаданные, наиболее эффективный способ — сгенерировать текст запроса динамически в цикле во встроенном языке 1С.
Разберем по шагам алгоритм решения:
Метаданные.РегистрыНакопления.ИмяРегистра.Регистраторы.ДокументМетаданные.Реквизиты.Найти("Реквизит1") <> Неопределено.ОБЪЕДИНИТЬ ВСЕ.Посмотрим на структуру итогового генерируемого запроса:
ВЫБРАТЬ
РН.Регистратор КАК Регистратор,
Док1.Реквизит1 КАК Реквизит1
ИЗ
РегистрНакопления.НашРегистр КАК РН
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ВидДокумента1 КАК Док1
ПО РН.Регистратор = Док1.Ссылка
ГДЕ
Док1.Реквизит1 = &ПараметрЗначение
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
РН.Регистратор КАК Регистратор,
Док2.Реквизит1 КАК Реквизит1
ИЗ
РегистрНакопления.НашРегистр КАК РН
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ВидДокумента2 КАК Док2
ПО РН.Регистратор = Док2.Ссылка
ГДЕ
Док2.Реквизит1 = &ПараметрЗначение
Данная структура исключает попадание в запрос документов, у которых реквизит отсутствует, и предотвращает ошибку превышения количества соединений в СУБД.
Проанализируем архитектурные решения задачи, которые позволяют упростить запросы и ускорить их выполнение:
ОбщийРеквизит в метаданных. Это облегчит работу с полем в запросах.ОпределяемыйТип.