Как правильно обращаться к реквизитам составного типа в запросе 1С и проверять его тип?

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

При написании запросов к регистрам сведений, измерения которых имеют составной тип данных (в частности, ЛюбаяСсылка), разработчики часто сталкиваются с синтаксическими ошибками и критическим падением производительности. Рассмотрим типичную ситуацию: требуется выбрать реквизиты конкретного документа (например, РеализацияТоваровУслуг) из регистра сведений и установить отбор по периоду и типу документа.

Проанализируем исходный вариант запроса, выявим синтаксические и архитектурные ошибки, а затем разберем правильные способы реализации такой выборки.

Синтаксические ошибки при проверке типа

В исходном запросе условие проверки типа было написано следующим образом:


ГДЕ
    ТИПЗНАЧЕНИЯ(Отфактуровка.Документ) = ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг)

Такая запись вызывает синтаксическую ошибку, так как функция ТИПЗНАЧЕНИЯ() возвращает значение с типом Тип, а функция ЗНАЧЕНИЕ() с переданным метаданным именем предназначена для получения предопределенных элементов, значений перечислений или пустых ссылок. Платформа ожидает увидеть конструкцию вроде ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг.ПустаяСсылка), но тогда типы выражений слева и справа не совпадут (тип против ссылки).

Для корректного сравнения типов в языке запросов 1С предусмотрены два основных синтаксических механизма:

  1. Использование функции ТИП(): Сравнение функции ТИПЗНАЧЕНИЯ() с литералом типа:
    
    ГДЕ
        ТИПЗНАЧЕНИЯ(Отфактуровка.Документ) = ТИП(Документ.РеализацияТоваровУслуг)
    
  2. Использование логического оператора ССЫЛКА: Это наиболее естественный и рекомендуемый способ проверки принадлежности ссылки к конкретной таблице метаданных:
    
    ГДЕ
        Отфактуровка.Документ ССЫЛКА Документ.РеализацияТоваровУслуг
    

Технические риски разыменования поля типа ЛюбаяСсылка

Синтаксическое исправление условия отбора не решает главной проблемы исходного запроса — неявного разыменования составного ссылочного поля через точку (Отфактуровка.Документ.Номер, Отфактуровка.Документ.Дата и т.д.). Выясним причину, почему такое обращение опасно для информационной базы:

  1. Превышение лимита таблиц в СУБД: Тип ЛюбаяСсылка включает в себя абсолютно все ссылочные объекты конфигурации: документы, справочники, планы видов характеристик, планы счетов и другие. Когда транслятор 1С встречает конструкцию разыменования поля составного типа через точку, он строит неявные соединения LEFT JOIN со всеми таблицами, входящими в составной тип. Если в метаданных суммарно более 256 таблиц, СУБД Microsoft SQL Server аварийно прервет выполнение запроса из-за превышения жесткого системного лимита на количество соединяемых таблиц в одном выражении.
  2. Каскадные неявные соединения: В выражении Отфактуровка.Документ.ДоговорКонтрагента.Номер происходит двойное разыменование. Сначала соединяются все возможные таблицы документов, а затем к найденному договору подсоединяется таблица справочника договоров. Это приводит к формированию колоссального плана выполнения в СУБД и многократному росту потребления оперативной памяти сервером.
  3. Игнорирование индексов: Применение фильтра по дате вида Отфактуровка.Документ.Дата МЕЖДУ ... не позволяет СУБД использовать индекс регистра по измерению Документ. Платформе приходится выполнять полное сканирование таблицы регистра (Table Scan или Index Scan) с параллельным разыменованием всех связанных таблиц.

Способ 1. Уточнение типа с помощью функции ВЫРАЗИТЬ

Если требуется оставить регистр сведений в качестве ведущей таблицы, необходимо жестко ограничить составной тип измерения до конкретного документа с помощью функции ВЫРАЗИТЬ() как в секции ВЫБРАТЬ, так и в условиях ГДЕ. Это указывает платформе на необходимость построить соединение только с одной физической таблицей Документ.РеализацияТоваровУслуг:


ВЫБРАТЬ
    ВЫРАЗИТЬ(Отфактуровка.Документ КАК Документ.РеализацияТоваровУслуг).Номер КАК Номер,
    ВЫРАЗИТЬ(Отфактуровка.Документ КАК Документ.РеализацияТоваровУслуг).Дата КАК Дата,
    ВЫРАЗИТЬ(Отфактуровка.Документ КАК Документ.РеализацияТоваровУслуг).ДоговорКонтрагента.Номер КАК ДоговорНомер,
    ВЫРАЗИТЬ(Отфактуровка.Документ КАК Документ.РеализацияТоваровУслуг).ДоговорКонтрагента.Дата КАК ДоговорДата,
    ВЫРАЗИТЬ(Отфактуровка.Документ КАК Документ.РеализацияТоваровУслуг).ЕстьПодписанныйОригинал КАК ЕстьПодписанныйОригинал,
    ВЫРАЗИТЬ(Отфактуровка.Документ КАК Документ.РеализацияТоваровУслуг).Ответственный КАК Ответственный
ИЗ
    РегистрСведений.Отфактуровка КАК Отфактуровка
ГДЕ
    Отфактуровка.Документ ССЫЛКА Документ.РеализацияТоваровУслуг
    И ВЫРАЗИТЬ(Отфактуровка.Документ КАК Документ.РеализацияТоваровУслуг).Дата МЕЖДУ &НачДата И &КонДата

Способ 2. Оптимальный: смена ведущей таблицы запроса

Рассмотрим более производительный вариант. Так как фильтрация строится по периоду дат документа, эффективнее сделать источником выборки сам документ РеализацияТоваровУслуг, а регистр сведений присоединить через ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Поле Дата у документов входит в состав кластерного индекса, поэтому выборка за период выполнится практически мгновенно:


ВЫБРАТЬ
    Реализация.Номер КАК Номер,
    Реализация.Дата КАК Дата,
    Реализация.ДоговорКонтрагента.Номер КАК ДоговорНомер,
    Реализация.ДоговорКонтрагента.Дата КАК ДоговорДата,
    Реализация.ЕстьПодписанныйОригинал КАК ЕстьПодписанныйОригинал,
    Реализация.Ответственный КАК Ответственный
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.Отфактуровка КАК Отфактуровка
        ПО Отфактуровка.Документ = Реализация.Ссылка
ГДЕ
    Реализация.Дата МЕЖДУ &НачДата И &КонДата

Такой подход избавляет запрос от нагромождения конструкций ВЫРАЗИТЬ(), исключает риск лишних соединений и гарантирует корректную работу с индексами базы данных.

Способ 3. Пакетный запрос с временной таблицей

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


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Отфактуровка.Документ КАК ДокументСсылка
ПОМЕСТИТЬ ВТ_Документы
ИЗ
    РегистрСведений.Отфактуровка КАК Отфактуровка
ГДЕ
    Отфактуровка.Документ ССЫЛКА Документ.РеализацияТоваровУслуг
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Реализация.Номер КАК Номер,
    Реализация.Дата КАК Дата,
    Реализация.ДоговорКонтрагента.Номер КАК ДоговорНомер,
    Реализация.ДоговорКонтрагента.Дата КАК ДоговорДата,
    Реализация.ЕстьПодписанныйОригинал КАК ЕстьПодписанныйОригинал,
    Реализация.Ответственный КАК Ответственный
ИЗ
    ВТ_Документы КАК ВТ_Документы
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
        ПО ВТ_Документы.ДокументСсылка = Реализация.Ссылка
ГДЕ
    Реализация.Дата МЕЖДУ &НачДата И &КонДата

Архитектурные рекомендации

Для предотвращения подобных сложностей при проектировании конфигурации следует соблюдать стандарты разработки 1С:

  1. Ограничение состава типов: Избегайте назначения типа ЛюбаяСсылка для реквизитов и измерений. Указывайте только те конкретные типы документов, которые действительно могут быть записаны в данный регистр.
  2. Денормализация: Если к регистру сведений регулярно выполняются запросы с отбором по дате документа или его реквизитам, вынесите эти поля непосредственно в структуру регистра сведений в виде отдельных измерений или реквизитов с включенным свойством Индексировать. Это позволит получать нужные данные напрямую из регистра без соединений с таблицами документов.
← На главную