При построении отчетов и выборок в платформе 1С:Предприятие разработчики часто сталкиваются с задачей установки отборов по справочникам. Если пользователь выбирает конкретный элемент, обычно достаточно простого равенства (=). Однако если в качестве условия передается группа справочника (папка), возникает вопрос: какую конструкцию использовать — В или В ИЕРАРХИИ, в чем их принципиальная разница и как это влияет на производительность запроса?
Разберем детально особенности работы каждого оператора, проанализируем поведение системы и рассмотрим оптимальные варианты построения запросов.
Для понимания механизма работы сравним назначение и поведение обоих операторов языка запросов 1С:
В (проверка вхождения в список):
Конструкция проверяет точное совпадение значения поля со списком значений, массивом или результатом вложенного запроса. Если в параметр передать группу справочника, оператор В выполнит поиск только тех записей, где в поле записана непосредственно сама эта группа. Дочерние элементы и вложенные подпапки в выборку не попадут.
В ИЕРАРХИИ (проверка принадлежности к ветке иерархии):
Это специализированная конструкция платформы 1С, не имеющая прямого аналога в стандартном синтаксисе SQL. Она проверяет, входит ли проверяемое значение в иерархическую ветку переданного узла (родителя). В результат попадают как сам указанный узел, так и все подчиненные ему элементы и подгруппы на всех уровнях вложенности.
Важная особенность: если в параметр условия с оператором В ИЕРАРХИИ передать не группу, а конечный элемент, запрос отработает корректно и вернет только этот элемент (так как элемент является вершиной собственной ветки). Таким образом, оператор В ИЕРАРХИИ является универсальным для отбора как по группам, так и по отдельным элементам.
Рассмотрим, как часто пытаются решить задачу разделения элементов и групп и как сделать код проще и надежнее.
Нередко разработчики пишут избыточные проверки с помощью метода ЭтоГруппа(), усложняя текст модуля:
Если ЗначениеЗаполнено(КонтрагентОтбор) И НЕ КонтрагентОтбор.ЭтоГруппа() Тогда
Запрос.Текст = Запрос.Текст + " И Таблица.Ссылка.Контрагент = &Контрагент";
ИначеЕсли ЗначениеЗаполнено(КонтрагентОтбор) И КонтрагентОтбор.ЭтоГруппа() Тогда
Запрос.Текст = Запрос.Текст + " И Таблица.Ссылка.Контрагент В ИЕРАРХИИ(&Контрагент)";
КонецЕсли;
Поскольку конструкция В ИЕРАРХИИ одинаково успешно находит и конкретный элемент, и группу со всеми вложенными позициями, условие можно сократить без потери функциональности:
Если ЗначениеЗаполнено(КонтрагентОтбор) Тогда
Запрос.Текст = Запрос.Текст + "
| И Таблица.Ссылка.Контрагент В ИЕРАРХИИ(&Контрагент)";
Запрос.УстановитьПараметр("Контрагент", КонтрагентОтбор);
КонецЕсли;
Кроме того, в параметр конструкции В ИЕРАРХИИ можно передавать не только одиночную ссылку, но и массив ссылок или список значений (например, несколько групп). Платформа автоматически отберет подчиненные элементы для каждого указанного узла.
Несмотря на удобство, оператор В ИЕРАРХИИ требует осторожного применения из-за особенностей его трансляции на уровень СУБД:
В ИЕРАРХИИ платформа 1С выполняет обращение к специальным служебным таблицам иерархии метаданных. На уровне SQL генерируются сложные подзапросы или соединения, что нередко приводит к отказу оптимизатора СУБД от использования индексов и переходу к сканированию всей таблицы (Table Scan / Index Scan).В ИЕРАРХИИ обязательно должно накладываться в параметрах виртуальной таблицы (например, среза последних или остатков), а не в секции ГДЕ, иначе сначала в память будут прочитаны все записи регистра, и лишь затем отфильтрованы.Проанализируем проверенные методы повышения быстродействия при работе с иерархическими отборами:
Если запрос соединяет несколько больших таблиц, эффективнее всего сначала выбрать все входящие в иерархию элементы во временную таблицу и проиндексировать ее:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_СоставГруппы
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ(&ГруппаНоменклатуры)
ИНДЕКСИРОВАТЬ ПО
Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.КоличествоОборот КАК Количество
ИЗ
РегистрНакопления.Продажи.Обороты(
&НачалоПериода,
&КонецПериода,
,
Номенклатура В (ВЫБРАТЬ ВТ_СоставГруппы.Ссылка ИЗ ВТ_СоставГруппы КАК ВТ_СоставГруппы)) КАК ПродажиОбороты
Для небольших справочников с неглубокой структурой можно заранее получить массив ссылок отдельным легким запросом, после чего передать его в основной запрос через оператор точного вхождения В (&МассивСсылок), что позволит СУБД построить оптимальный план выполнения.
При разработке отчетов рекомендуется передавать задачу фильтрации механизмам СКД. Компоновщик данных динамически формирует оптимальный текст SQL-запроса, корректно обрабатывая виды сравнения В иерархии и В иерархии (списка).