В практике разработки на платформе 1С:Предприятие часто возникает задача фильтрации данных виртуальных таблиц (например, СрезПоследних или Обороты) по определенному списку значений. Рассмотрим классическую ситуацию: необходимо получить накладные из периодического регистра сведений, оформленные по конкретному списку договоров. Существует несколько способов решения этой задачи, и выбор наиболее эффективного напрямую влияет на быстродействие системы, особенно при работе с крупными базами данных под управлением MS SQL Server или PostgreSQL.
Согласно общим методическим рекомендациям, наиболее предпочтительным вариантом является наложение условий непосредственно в параметрах виртуальной таблицы. Разберем, почему это важно. Когда мы указываем условие в параметре (например, &УсловиеДоговор), платформа стремится передать этот фильтр максимально глубоко в SQL-запрос. Это позволяет СУБД отсечь ненужные записи еще на этапе первичной выборки из физических таблиц регистра.
Рассмотрим пример правильного оформления условия в параметрах:
ВЫБРАТЬ
РегистрСведенийСрезПоследних.Договор,
РегистрСведенийСрезПоследних.Накладная
ИЗ
РегистрСведений.СведенияОНакладных.СрезПоследних(&Период, Договор В (&СписокДоговоров)) КАК РегистрСведенийСрезПоследних
Если Договор является измерением регистра, то СУБД сможет эффективно использовать существующие индексы. Однако стоит помнить об ограничении: если &СписокДоговоров содержит огромное количество элементов, это может привести к деградации производительности или даже ошибке переполнения SQL-запроса.
Часто возникает дилемма: передать список через подзапрос в условии ГДЕ или использовать конструкцию В (ВЫБРАТЬ...) прямо в параметре виртуальной таблицы. Проанализируем технические нюансы работы СУБД в этих случаях:
ПОМЕСТИТЬ) СУБД автоматически собирает по ней статистику. Это позволяет оптимизатору «видеть» объем данных и строить правильные соединения.Пример использования проиндексированной временной таблицы в параметре:
// Сначала помещаем список во временную таблицу ВТ_Договоры с индексацией
// Затем используем её в основном запросе
ВЫБРАТЬ
Срез.Договор,
Срез.Накладная
ИЗ
РегистрСведений.СведенияОНакладных.СрезПоследних(&Период, Договор В (ВЫБРАТЬ Т.Договор ИЗ ВТ_Договоры КАК Т)) КАК Срез
Вариант с использованием ВНУТРЕННЕЕ СОЕДИНЕНИЕ со срезом последних также имеет право на жизнь, но он считается наиболее «опасным» для производительности, особенно в PostgreSQL. Выясним причину: виртуальная таблица СрезПоследних сама по себе является сложным вложенным запросом с группировками или оконными функциями на уровне SQL. Соединение одного сложного подзапроса с другим подзапросом или таблицей часто сбивает оптимизатор с толку.
Важный момент: Если вы все же используете соединение, убедитесь, что соединяемые поля типизированы. Соединение по полям составного типа или по полям типа ЛюбаяСсылка (например, Регистратор) приводит к лавинообразному росту количества соединений с таблицами метаданных, что может полностью остановить выполнение запроса.
Проанализируем основные правила, которые помогут избежать проблем с быстродействием:
ГДЕ. Фильтрация в ГДЕ происходит уже после того, как виртуальная таблица будет сформирована в памяти СУБД, что избыточно.Договор является первым (или единственным) в индексе регистра.ИЛИ в условиях часто приводит к полному сканированию таблицы (Scan) вместо быстрого поиска по индексу (Seek). Если нужно отобрать данные по разным критериям, лучше использовать ОБЪЕДИНИТЬ ВСЕ.Таким образом, для получения максимального быстродействия рекомендуется использовать временные таблицы с индексацией, условия из которых передаются в параметры виртуальных таблиц. Это обеспечивает предсказуемость плана запроса и эффективное использование индексов СУБД.