В чем разница между отбором в параметрах виртуальной таблицы и секции ГДЕ для регистра сведений?

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

При написании запросов к периодическим регистрам сведений разработчики часто сталкиваются с вопросом: где правильнее указывать условия — в параметрах виртуальной таблицы (например, СрезПоследних или СрезПервых) или в секции ГДЕ? На первый взгляд может показаться, что при отборе по ключевым полям результат не меняется. Однако в зависимости от того, на какое поле накладывается условие (измерение или ресурс), а также от структуры самого запроса, результат и скорость его выполнения могут кардинально различаться.

Разберем подробно механику работы платформы 1С, выясним причину различий в результатах и проанализируем примеры на практике.

Механика работы: параметры виртуальной таблицы против секции ГДЕ

Чтобы понять различия, рассмотрим, как платформа 1С и СУБД обрабатывают условия:

  1. Условие в параметрах виртуальной таблицы: фильтрация данных происходит до вычисления среза. Платформа формирует вложенный запрос к физической таблице базы данных, сразу отсекая лишние записи, и строит срез (получает записи с максимальной или минимальной датой) только по тем строкам, которые уже удовлетворили условию.
  2. Условие в секции ГДЕ: сначала платформа строит виртуальную таблицу среза по всем данным регистра (или по всем комбинациям измерений), и только затем к полученному итоговому результату применяется внешнее условие фильтрации.

Отбор по измерениям: в чем разница?

Проанализируем поведение запроса при фильтрации по измерениям регистра (например, по сотруднику, валюте или договору):

  1. Состав выборки: При простом запросе к одной таблице результат будет одинаковым. Однако при использовании конструкции ЛЕВОЕ СОЕДИНЕНИЕ поведение меняется. Если отбор по измерению поместить в секцию ГДЕ, условие отсечет строки со значением NULL, неявно превратив соединение во внутреннее. Если же фильтр задан в параметрах виртуальной таблицы, левое соединение сохранит все исходные строки левой таблицы.
  2. Производительность: С точки зрения быстродействия отбор всегда следует помещать в параметры виртуальной таблицы. В этом случае СУБД выполняет группировку и агрегацию только для ограниченного набора строк, эффективно используя существующие индексы таблицы. Фильтрация через ГДЕ заставляет СУБД сначала рассчитать срез по всей таблице регистра, что на больших объемах данных приводит к существенному замедлению.

Отбор по ресурсам: принципиальная разница в результате

Если условие накладывается на ресурс регистра сведений, выборки данных в большинстве случаев будут абсолютно разными. Рассмотрим классический пример с периодическим регистром сведений КурсыВалют, содержащим измерение Валюта и ресурс Курс.

Представим следующие данные в регистре:

  1. Период: 01.01.2024, Валюта: Доллар, Курс: 30.25
  2. Период: 01.01.2024, Валюта: Евро, Курс: 40.50
  3. Период: 01.02.2024, Валюта: Доллар, Курс: 28.30
  4. Период: 01.02.2024, Валюта: Евро, Курс: 41.20

Поставим задачу: выбрать валюты на самую раннюю дату, курс которых был меньше 30.

Посмотрим на первый вариант — наложение условия в параметрах виртуальной таблицы:


ВЫБРАТЬ
    КурсыВалютСрезПервых.Период КАК Период,
    КурсыВалютСрезПервых.Валюта КАК Валюта,
    КурсыВалютСрезПервых.Курс КАК Курс
ИЗ
    РегистрСведений.КурсыВалют.СрезПервых(, Курс < 30) КАК КурсыВалютСрезПервых

В этом случае платформа сначала отфильтрует физическую таблицу, оставив только запись с курсом 28.30, и затем возьмет срез первых по отфильтрованным строкам. Результатом будет одна строка: Доллар, 01.02.2024, 28.30.

Теперь рассмотрим второй вариант — перенос условия в секцию ГДЕ:


ВЫБРАТЬ
    КурсыВалютСрезПервых.Период КАК Период,
    КурсыВалютСрезПервых.Валюта КАК Валюта,
    КурсыВалютСрезПервых.Курс КАК Курс
ИЗ
    РегистрСведений.КурсыВалют.СрезПервых КАК КурсыВалютСрезПервых
ГДЕ
    КурсыВалютСрезПервых.Курс < 30

В этом сценарии платформа сначала построит срез первых по всему регистру (получит записи от 01.01.2024: Доллар с курсом 30.25 и Евро с курсом 40.50), а затем применит фильтр Курс < 30. Ни одна из записей среза не удовлетворяет условию, поэтому результат запроса будет пустым.

Аналогичный пример: срез последних по окладам сотрудников

Проанализируем ситуацию с регистром окладов сотрудников:

  1. Условие в секции ГДЕ: ГДЕ Оклад > 50000 — запрос вернет сотрудников, у которых текущий актуальный оклад превышает 50 000. Сотрудники, у которых оклад когда-то был выше, но сейчас снизился, в выборку не попадут.
  2. Условие в параметрах: СрезПоследних(, Оклад > 50000) — запрос найдет последнюю запись для каждого сотрудника, когда его оклад превышал 50 000, даже если сейчас его ставка меньше или он вовсе переведен на другую должность.

Практические рекомендации по написанию запросов

  1. Для фильтрации по измерениям: всегда передавайте условия в параметры виртуальной таблицы. Это обеспечивает правильное использование индексов СУБД и предотвращает избыточные вычисления.
  2. Для передачи списков значений: если в параметр передается большой массив элементов (например, более 20 значений), рекомендуется поместить этот список во временную таблицу, проиндексировать ее и передать условие в параметр через подзапрос вида Измерение В (ВЫБРАТЬ Поле ИЗ ВТ_Критерии).
  3. Для фильтрации по ресурсам: четко определяйте бизнес-логику задачи. Если требуется узнать «текущее состояние, удовлетворяющее критерию», условие накладывается в секции ГДЕ. Если требуется «наиболее свежая запись среди тех, которые соответствовали критерию», условие накладывается в параметрах виртуальной таблицы.
← На главную