Разработка и Конфигурация · 13 мин
Как работает запрос в 1С: разбор для разработчиков и консультантов
Как работает запрос в 1С: этапы выполнения, синтаксис языка запросов, параметры, пакеты, временные таблицы, оптимизация и типичные ошибки разработчиков.
Запрос в 1С — это основной способ получения данных из информационной базы: отчёты, обработки, проведение документов и движения по регистрам внутри себя почти всегда опираются на запросы. Понимание того, как платформа преобразует текст на встроенном языке запросов в SQL и возвращает результат, помогает писать быстрый и предсказуемый код, а не подбирать конструкции методом проб и ошибок.
Механизм устроен в несколько слоёв. Разработчик формирует текст запроса на языке, похожем на SQL, но с особенностями 1С: виртуальные таблицы, разыменование через точку, представления ссылок. Платформа анализирует этот текст, строит план и транслирует его в запрос к СУБД (MS SQL Server, PostgreSQL, Oracle, IBM Db2) или к файловой базе. Результат возвращается в виде выборки, таблицы значений или дерева.
Ниже разобраны этапы выполнения запроса, структура текста, работа с параметрами и временными таблицами, а также типичные ошибки, из-за которых запросы работают медленно или возвращают неожиданные данные.
Что происходит после вызова метода Выполнить()
Когда в коде вызывается Запрос.Выполнить(), платформа проходит несколько этапов. Сначала текст запроса разбирается синтаксическим анализатором: проверяются ключевые слова, имена таблиц и полей, соответствие метаданным конфигурации. Если в тексте указано несуществующее поле или таблица, ошибка возникает уже на этом этапе — до обращения к базе данных.
Затем платформа строит внутреннее представление запроса и транслирует его в диалект SQL конкретной СУБД. Именно здесь «магия» 1С превращается в обычные соединения таблиц: разыменование Документ.Контрагент.Наименование становится LEFT JOIN к таблице справочника, а обращение к виртуальной таблице остатков — вложенным запросом с группировкой по регистру накопления.
СУБД выполняет полученный SQL по своему плану и возвращает набор данных платформе. Платформа материализует его в объект РезультатЗапроса, из которого дальше получают выборку (Выбрать()) или выгружают в таблицу значений (Выгрузить()). Важно понимать: вся фильтрация и соединения выполняются на сервере СУБД, а не в памяти приложения 1С.
Структура текста запроса: секции и их назначение
Текст запроса состоит из секций в строгом порядке: ВЫБРАТЬ (SELECT), ИЗ (FROM) с соединениями, ГДЕ (WHERE), СГРУППИРОВАТЬ ПО (GROUP BY), ИМЕЮЩИЕ (HAVING), УПОРЯДОЧИТЬ ПО (ORDER BY), ИТОГИ (TOTALS). Дополнительно используются ОБЪЕДИНИТЬ (UNION) и конструкция пакетного запроса ; ПОМЕСТИТЬ.
Минимальный рабочий запрос выглядит так:
ВЫБРАТЬ
Товары.Ссылка КАК Товар,
Товары.Наименование
ИЗ
Справочник.Номенклатура КАК Товары
ГДЕ
НЕ Товары.ПометкаУдаления
Псевдонимы (КАК) стоит задавать всегда: они делают код читаемым и защищают от конфликтов имён при доработках. Секция ИТОГИ специфична для 1С — она добавляет в выборку группировочные записи и позволяет обходить результат иерархически, что удобно для отчётов с подытогами.
Параметры запроса: зачем нужны и как передаются
Параметры — это значения, подставляемые в запрос через амперсанд: ГДЕ Документ.Дата >= &НачалоПериода. Значения назначаются методом Запрос.УстановитьПараметр("НачалоПериода", ДатаНачала) до вызова Выполнить().
Использовать параметры нужно всегда вместо конкатенации значений в текст запроса. Подстановка строкой не только создаёт риск ошибок с типами (даты, строки с кавычками), но и мешает СУБД повторно использовать план запроса: каждый новый текст компилируется заново, что заметно нагружает сервер при массовых операциях.
Особый случай — передача списка значений или таблицы значений в параметр для условия В (&СписокТоваров). Платформа умеет разворачивать массивы и списки в список значений SQL, а таблицу значений можно передать и затем поместить во временную таблицу для соединения — это стандартный приём для отбора по произвольному набору данных.
- 1Сформулируйте, какие данные нужны и из каких таблиц они берутся
- 2Напишите текст в консоли запросов или конструкторе, задайте псевдонимы
- 3Замените все литеральные значения на параметры через &
- 4Проверьте результат на тестовой копии базы: количество строк и итоги
- 5Оцените время выполнения на объёме, близком к рабочему
- 6Перенесите текст в код, установите параметры и выполните запрос
Пакетные запросы и временные таблицы
Пакетный запрос — это несколько запросов в одном тексте, разделённые точкой с запятой. Промежуточные результаты сохраняются во временные таблицы с помощью ПОМЕСТИТЬ ИмяТаблицы, а финальный запрос читает из них. Временные таблицы живут в пределах одного выполнения пакета или в менеджере временных таблиц (МенеджерВременныхТаблиц), если он назначен явно.
Типовой сценарий: сначала отобрать нужные документы во временную таблицу ВТ_Документы, затем соединить её с виртуальной таблицей остатков. Такой подход резко сокращает объём обрабатываемых данных, потому что виртуальная таблица считается только по отобранным измерениям, а не по всему регистру.
ВЫБРАТЬ
Продажи.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_Товары
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Продажи
ГДЕ
Продажи.Ссылка = &Документ
;
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
, Номенклатура В (ВЫБРАТЬ Т.Номенклатура ИЗ ВТ_Товары КАК Т)) КАК Остатки
После использования временные таблицы рекомендуется уничтожать (УНИЧТОЖИТЬ ВТ_Товары), особенно в длинных пакетах: они занимают память или дисковое пространство на сервере СУБД до конца выполнения пакета.
Виртуальные таблицы и их параметры
У регистров накопления и сведений есть виртуальные таблицы: Остатки, Обороты, СрезПервых, СрезПоследних. Их параметры задаются в скобках после имени таблицы: период, условие отбора. Ключевое правило — условия фильтрации передавать именно в параметры виртуальной таблицы, а не в секцию ГДЕ внешнего запроса.
Разница принципиальна. Если отбор по складу указан в параметрах виртуальной таблицы, СУБД агрегирует только движения по этому складу. Если то же условие написано в ГДЕ, платформа сначала вычислит остатки по всем складам, а потом отфильтрует строки — на больших регистрах это разница между секундами и минутами.
Для таблицы Обороты обязательно задавайте период: обороты без ограничения дат считаются по всей истории регистра. Аналогично СрезПоследних без указания периода вернёт актуальные значения, что корректно, но на больших регистрах сведений тоже требует оценки стоимости.
Сравнение вариантов отбора
Агрегация идёт только по нужным данным, быстрее и дешевле. Ограничение: условия только по измерениям и реквизитам, доступным в параметрах.
Сначала вычисляется вся виртуальная таблица, потом фильтрация. Подходит только для отборов по вычисляемым полям результата.
Оптимально при отборе по произвольному списку значений из другой таблицы. Требует аккуратной работы с менеджером временных таблиц.
Как платформа возвращает результат: выборка, таблица, дерево
Метод Выбрать() возвращает выборку — последовательный курсор по строкам результата. Выборка экономит память при обходе больших результатов, но не позволяет вернуться назад и узнать количество строк заранее. Обход выполняется циклом Пока Выборка.Следующий() Цикл.
Метод Выгрузить() материализует весь результат в таблицу значений в памяти. Это удобно для произвольного доступа, сортировок и поиска, но при сотнях тысяч строк расходует заметный объём памяти на сервере. Метод Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) строит дерево значений — для иерархических отчётов.
Признак правильного выбора: если данные нужно один раз последовательно обработать — берите выборку; если нужен многократный доступ, поиск или передача на клиента — таблицу значений; если результат с итогами по уровням — дерево.
Как проверить результат
Совпадает с ожидаемым по логике отбора
Строк заметно больше — вероятно, лишнее соединение без условия (декартово произведение)
Стабильно при повторных запусках и растёт пропорционально объёму данных
Резко растёт при небольшом увеличении периода — не используются индексы или параметры виртуальной таблицы
Суммы совпадают со стандартными отчётами конфигурации
Расхождения — проверьте период, отборы и дублирование строк из-за соединений
Производительность: индексы, соединения и типовые приёмы
Скорость запроса определяется тем, может ли СУБД использовать индексы. В 1С индексы создаются автоматически по ключевым полям и по реквизитам с включённым свойством «Индексировать». Отборы и соединения по неиндексированным реквизитам приводят к полному сканированию таблицы.
Практические правила, которые дают основной эффект:
- соединяйте таблицы по ссылочным полям (Ссылка), а не по строковым или числовым реквизитам;
- избегайте соединений с вложенными запросами и виртуальными таблицами без необходимости — часто достаточно предварительно поместить данные во временную таблицу;
- не используйте
СОЕДИНЕНИЕпо условию с функциями (ПОДСТРОКА,ГОД) — это отключает индексы; - выбирайте только нужные поля:
ВЫБРАТЬ *и разыменование лишних полей увеличивают объём соединений; - для проверки существования записей используйте
ВЫБРАТЬ ПЕРВЫЕ 1вместо полного списка.
Для диагностики в клиент-серверном варианте полезен технологический журнал с событиями DBMSSQL и план запроса средствами СУБД. В файловом варианте ориентируйтесь на замеры времени и логику отборов — инструменты планов там недоступны.
Частые вопросы о работе запросов в 1С
Чем запрос отличается от обхода таблицы методом Выбрать() у объекта?
Объектный метод Справочники.Номенклатура.Выбрать() читает записи по одной и создаёт объекты в памяти — это медленно при больших объёмах и не умеет соединения и группировки. Запрос выполняется целиком на стороне СУБД и возвращает только нужные поля, поэтому для выборки данных почти всегда предпочтительнее.
Почему запрос в консоли работает быстро, а в коде медленно?
Чаще всего причина в параметрах: в консоли значения подставлены литералами, а в коде передаются параметрами с типом, который СУБД не может сопоставить с индексом (например, строка большей длины). Проверьте, что типы параметров точно соответствуют типам полей, и что условия не обёрнуты функциями.
Когда использовать ОБЪЕДИНИТЬ, а когда ОБЪЕДИНИТЬ ВСЕ?
ОБЪЕДИНИТЬ устраняет дубликаты строк, что требует дополнительной сортировки и хеширования на СУБД. Если наборы заведомо не пересекаются (например, движения двух разных регистров), используйте ОБЪЕДИНИТЬ ВСЕ — это быстрее и не меняет результат.
Можно ли выполнять запросы в фоновом задании?
Да, запросы выполняются в фоновых заданиях без ограничений — это стандартный способ вынести тяжёлую обработку из сеанса пользователя. Учтите, что временные таблицы и менеджер временных таблиц должны создаваться внутри того же фонового задания, а результат нужно возвращать через помещение во временное хранилище.
Что делает конструкция ДЛЯ ИЗМЕНЕНИЯ?
ДЛЯ ИЗМЕНЕНИЯ накладывает управляемую блокировку на читаемые данные до конца транзакции, чтобы другие сеансы не изменили их параллельно. Применяется при проведении документов, когда остатки сначала читаются, а потом списываются. Вне транзакции конструкция вызовет ошибку, а лишнее её использование без необходимости увеличивает конкуренцию за блокировки.
Как посмотреть, какой SQL платформа отправила в СУБД?
Включите технологический журнал на сервере 1С с фильтром по событиям DBMSSQL (или DBPOSTGRS, DBORACLE в зависимости от СУБД) — в логе будет виден итоговый текст SQL и длительность выполнения. Это основной инструмент анализа, когда запрос ведёт себя неожиданно.
Что важно запомнить
Запрос в 1С компилируется платформой в SQL и выполняется на стороне СУБД. Используйте параметры вместо подстановки значений, отборы по виртуальным таблицам задавайте в их параметрах, промежуточные данные помещайте во временные таблицы, а результат обходите выборкой, если не нужен произвольный доступ. Отладку тяжёлых запросов проводите на копии базы с анализом технологического журнала.