К статье
Практический материал

Разработка и Конфигурация · 11 мин

Зачем нужны вложенные запросы в 1С и как их применять правильно

Зачем используют вложенные запросы в 1С: когда они оправданы, как писать и оптимизировать, какие есть альтернативы и типичные ошибки разработчиков.

Вложенный запрос в 1С — это запрос, помещённый внутрь другого запроса: в секцию выборки полей, в условие отбора или в качестве источника данных. Встроенный язык запросов 1С поддерживает такую конструкцию, и она регулярно встречается в типовых конфигурациях. Однако у начинающих разработчиков вложенные запросы вызывают вопросы: когда они действительно нужны, а когда только замедляют работу.

Главная причина использовать вложенный запрос — необходимость обработать данные в два логических шага: сначала сгруппировать или отфильтровать записи, а затем по результату выполнить основную выборку. Например, сначала найти максимальную дату документа по каждому контрагенту, а потом получить сами документы. Одним «плоским» запросом такая задача решается с трудом или не решается вовсе.

При этом вложенность — не единственный способ. В 1С есть временные таблицы и пакетные запросы, которые часто работают быстрее и читаются легче. Понимание разницы между этими подходами — ключевой навык при оптимизации медленных отчётов и обработок.

Ниже разобраны практические сценарии применения вложенных запросов, их ограничения, альтернативы и способы проверить, что запрос работает эффективно.

Что такое вложенный запрос и где он встречается

Вложенный запрос — это конструкция (ВЫБРАТЬ ... ), размещённая внутри другого запроса. В языке запросов 1С допускается три основных места размещения: источник данных в секции ИЗ, условие в секции ГДЕ (например, ГДЕ Поле В (ВЫБРАТЬ ...)) и, реже, в списке выбираемых полей.

Типичный пример — выборка документов с последними ценами. Сначала внутренний запрос группирует регистр сведений по номенклатуре и находит максимальный период, затем внешний запрос соединяет этот результат с самим регистром, чтобы получить значение цены. Это классический шаблон «последние значения», который встречается почти в каждой конфигурации.

Важно понимать: вложенный запрос не выполняется «отдельно» в привычном смысле. Платформа передаёт весь текст в СУБД, и та сама решает, как его исполнить — материализовать во временную структуру, развернуть в соединение или переписать иначе. План выполнения может отличаться от того, что представляет разработчик.

Основные сценарии, где вложенные запросы оправданы

Первый сценарий — получение среза последних или первых значений без использования виртуальных таблиц. Если регистр сведений не имеет подходящей виртуальной таблицы или нужен нестандартный отбор, вложенный запрос с группировкой по МАКСИМУМ(Период) решает задачу напрямую.

Второй сценарий — двухшаговая агрегация. Например, нужно посчитать среднюю сумму продаж по менеджерам, но сначала — сумму продаж каждого менеджера по месяцам. Внутренний запрос группирует обороты, внешний — усредняет результаты. Без вложенности такое в одном запросе не выразить.

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

Как построить вложенный запрос среза последних
  1. 1
    Напишите внутренний запрос: сгруппируйте регистр по измерениям и возьмите МАКСИМУМ(Период)
  2. 2
    Поместите его в скобки в секцию ИЗ внешнего запроса и дайте псевдоним через КАК
  3. 3
    Соедините результат с таблицей регистра по измерениям и найденному периоду
  4. 4
    Выберите нужные ресурсы (цена, статус, ответственный) во внешнем запросе
  5. 5
    Проверьте результат на тестовых данных: каждой номенклатуре должна соответствовать одна строка

Вложенный запрос против временной таблицы: что выбрать

Временные таблицы — главная альтернатива вложенности. В пакетном запросе промежуточный результат помещается во временную таблицу (ПОМЕСТИТЬ ИмяТаблицы), которая затем используется в следующих запросах пакета. По смыслу это то же самое, что вложенный запрос, но оформленное отдельным шагом.

Разница практическая. Временная таблица материализуется один раз и индексируется (ИНДЕКСИРОВАТЬ ПО), что ускоряет соединения. Вложенный запрос может вычисляться повторно или порождать неоптимальный план, особенно на больших таблицах. Кроме того, пакетный запрос проще отлаживать: каждый шаг можно выполнить отдельно в консоли запросов и посмотреть промежуточный результат.

Сравнение подходов

Вложенный запрос

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

Временная таблица в пакетном запросе

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

Виртуальная таблица (СрезПоследних, Обороты)

Оптимальна, если задача стандартная: срез, остатки, обороты. Платформа и СУБД уже оптимизировали такие выборки. Ограничение — только предопределённые параметры.

Правило выбора простое: если подзапрос короткий и выбирает немного строк — вложенность допустима. Если промежуточный результат крупный, используется несколько раз или к нему нужен индекс — выносите его во временную таблицу.

Производительность: почему вложенные запросы тормозят

Наиболее частая причина медленной работы — вложенный запрос в условии ГДЕ ... В (...) по большой таблице. СУБД может выполнять его как вложенный цикл: для каждой строки внешней выборки заново проверять подзапрос. На миллионах записей это превращается в минуты ожидания.

Вторая причина — соединение с вложенным запросом без подходящих индексов. Результат подзапроса не имеет индексов (это не физическая таблица), поэтому соединение идёт полным перебором. Временная таблица с индексом решает проблему напрямую.

Третья причина — избыточные поля и отсутствие отборов во внутреннем запросе. Если подзапрос выбирает весь регистр, а потом внешний запрос отбрасывает 95% строк, СУБД делает лишнюю работу. Все возможные условия следует опускать на самый глубокий уровень.

Как проверить и оптимизировать запрос

Первый инструмент — консоль запросов. Выполните внутренний запрос отдельно и оцените: сколько строк он возвращает и сколько времени занимает. Если подзапрос сам по себе тяжёлый, проблема в нём, а не во внешней части.

Второй инструмент — технологический журнал и анализ плана запроса на стороне СУБД. Ищите признаки полного сканирования таблиц (Table Scan, Seq Scan) и вложенных циклов по большим выборкам. Их наличие — сигнал перенести подзапрос во временную таблицу с индексом.

Контрольные точки

Как проверить результат

Время выполнения на реальной базе
Норма

Запрос отрабатывает за время, приемлемое для интерактивной работы пользователя

Тревожный признак

Выполнение занимает десятки секунд или вызывает таймаут

Количество строк результата
Норма

Число строк соответствует ожидаемой логике (например, одна строка на номенклатуру в срезе)

Тревожный признак

Строки дублируются из-за соединения без полного ключа или, наоборот, теряются

План запроса в СУБД
Норма

Используются индексы, соединения по ключам

Тревожный признак

Полные сканирования больших таблиц, вложенные циклы по миллионам строк

Полезный приём — замер до и после. Зафиксируйте время исходного варианта, перепишите на временные таблицы, сравните. Оптимизация без замера часто превращается в гадание: иногда СУБД сама успешно разворачивает вложенный запрос, и переписывание ничего не даёт.

Типичные ошибки при работе с вложенными запросами

Ошибка номер один — многоуровневая вложенность «матрёшкой»: запрос в запросе в запросе. Такой текст невозможно отладить, а СУБД получает минимум свободы для оптимизации. Два уровня — разумный предел; дальше нужны временные таблицы.

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

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

Типичные ошибки
01
Вложенность в три и более уровней — запрос нечитаем, отладка невозможна, план выполнения непредсказуем
02
Условия отбора только во внешнем запросе — внутренний выбирает миллионы лишних строк
03
Соединение с подзапросом по неполному ключу — дублирование строк и неверные итоги
04
Ручной срез последних вместо виртуальной таблицы СрезПоследних — лишний код и потеря производительности
05
Использование В (ВЫБРАТЬ ...) по большой таблице без проверки плана — вложенные циклы и таймауты

Практические рекомендации и маршрут выбора

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

Маршрут решения

Как выбрать подход

Нужен срез последних или остатки по стандартному региструИспользуйте виртуальную таблицу (СрезПоследних, Остатки, Обороты) — не пишите вложенный запрос вручную
Подзапрос короткий, группирует данные и возвращает мало строкДопустим вложенный запрос — он компактен и не требует менеджера временных таблиц
Промежуточный результат большой или используется в нескольких местахПоместите его во временную таблицу пакетного запроса и проиндексируйте по полям соединения
Запрос медленный и план показывает полные сканированияВыносите подзапрос во временную таблицу с индексом и перепроверьте план выполнения

И последнее: любую оптимизацию проверяйте на данных, близких к реальным по объёму. Запрос, отлично работающий на тестовой базе с сотней документов, может оказаться непригодным на рабочей с миллионами записей.

Итог

Что важно запомнить

Вложенные запросы в 1С нужны для двухшаговой обработки данных: сначала группировка или отбор, затем основная выборка. Они уместны для коротких подзапросов, но при больших объёмах уступают временным таблицам с индексами. Стандартные задачи (срез, остатки, обороты) решайте виртуальными таблицами, а эффективность всегда проверяйте замером и планом запроса.

Частые вопросы

Сколько уровней вложенности допустимо в запросе 1С?

Технически платформа позволяет несколько уровней, но практический предел — два. Каждый следующий уровень резко усложняет чтение, отладку и план выполнения. При необходимости глубже переписывайте логику на пакетный запрос с временными таблицами.

Можно ли использовать вложенный запрос в списке выбираемых полей?

Технически в некоторых СУБД такое возможно, но в языке запросов 1С это не поддерживается как полноценный механизм. Для подобных задач используют соединение с подзапросом или временной таблицей в секции ИЗ.

Что быстрее: вложенный запрос или соединение таблиц?

Однозначного ответа нет — решает оптимизатор СУБД. Часто СУБД сама преобразует вложенный запрос в соединение. Если соединение написано явно и по индексированным полям, оно обычно предсказуемее. Сравнивайте варианты замером на реальных данных.

Почему запрос с условием В (ВЫБРАТЬ ...) работает медленно?

Как правило, потому что СУБД выполняет подзапрос как вложенный цикл по строкам внешней выборки или не может использовать индексы. Решение — переписать условие как соединение с временной таблицей, проиндексированной по полю отбора.

Нужен ли менеджер временных таблиц для вложенного запроса?

Нет. Вложенный запрос — часть одного текста запроса и не требует объекта МенеджерВременныхТаблиц. Менеджер нужен только при работе с пакетными запросами, где результат помещается во временную таблицу через ПОМЕСТИТЬ.

Как отладить сложный запрос с вложенностью?

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