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

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

Как работают запросы в 1С: руководство для разработчика

Разбираем, как работают запросы в 1С: синтаксис языка запросов, конструктор, виртуальные таблицы, пакетные запросы, временные таблицы и типичные ошибки разработчиков.

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

Запрос в 1С всегда проходит один и тот же путь: текст запроса анализируется платформой, транслируется в SQL для конкретной СУБД (MS SQL Server, PostgreSQL, Oracle, IBM Db2 или файловый вариант), а результат возвращается в виде выборки, таблицы значений или массива. Разработчик работает с объектом Запрос, задаёт текст, параметры и получает результат методом Выполнить().

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

Как устроен язык запросов 1С

Язык запросов 1С основан на стандарте SQL, но адаптирован под модель данных платформы. Основные секции знакомы любому, кто видел SQL: ВЫБРАТЬ (SELECT), ИЗ (FROM), ГДЕ (WHERE), СГРУППИРОВАТЬ ПО (GROUP BY), УПОРЯДОЧИТЬ ПО (ORDER BY), ИТОГИ ПО (TOTALS). Писать ключевые слова можно и на русском, и на английском — платформа понимает оба варианта.

Ключевое отличие от «чистого» SQL — источники данных. Вместо физических таблиц указываются объекты конфигурации: Справочник.Номенклатура, Документ.РеализацияТоваровУслуг, РегистрНакопления.Продажи. Платформа сама определяет, в каких физических таблицах лежат эти данные, и строит соответствующий SQL. Поэтому текст запроса не зависит от используемой СУБД — один и тот же запрос работает и в файловой базе, и на MS SQL Server.

Кроме выборки полей язык поддерживает соединения таблиц (ЛЕВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ), вложенные запросы, объединения (ОБЪЕДИНИТЬ), агрегатные функции (СУММА, КОЛИЧЕСТВО, МАКСИМУМ), условные выражения (ВЫБОР ... КОГДА ... ТОГДА ... КОНЕЦ) и работу с иерархией (В ИЕРАРХИИ).

Объект «Запрос»: как выполнить запрос из кода

Работа с запросом во встроенном языке строится по одной схеме: создаётся объект Запрос, заполняется свойство Текст, устанавливаются параметры через УстановитьПараметр(), затем вызывается Выполнить(). Результат можно обойти выборкой (Выбрать()) или выгрузить в таблицу значений (Выгрузить()).

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажиОбороты.Номенклатура КАК Номенклатура,
| СУММА(ПродажиОбороты.СуммаОборот) КАК Сумма
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
|СГРУППИРОВАТЬ ПО
| ПродажиОбороты.Номенклатура";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));
Результат = Запрос.Выполнить().Выгрузить();

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

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

Порядок выполнения запроса из кода
  1. 1
    Создайте объект: Запрос = Новый Запрос
  2. 2
    Заполните свойство Запрос.Текст текстом на языке запросов
  3. 3
    Установите все параметры через УстановитьПараметр
  4. 4
    Вызовите Результат = Запрос.Выполнить()
  5. 5
    Получите данные: Выбрать() для обхода или Выгрузить() в таблицу значений
  6. 6
    Проверьте результат: Результат.Пустой() или количество строк в выгрузке

Конструктор запроса: быстрый способ собрать текст

В конфигураторе текст запроса не обязательно писать вручную — встроенный конструктор запроса позволяет собрать его мышкой: выбрать таблицы, поля, условия, группировки и порядок сортировки. Конструктор вызывается из контекстного меню модуля («Конструктор запроса») и умеет разбирать уже существующий текст, если тот синтаксически корректен.

Отдельный инструмент — конструктор запроса с обработкой результата. Он не только формирует текст, но и генерирует готовый фрагмент кода: создание объекта запроса, установку параметров, обход выборки по группировкам. Это удобно как шаблон для дальнейшей доработки, особенно когда нужны итоги по иерархии.

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

Виртуальные таблицы регистров: остатки, обороты и срезы

Чаще всего запросы в типовых конфигурациях обращаются не к самим регистрам, а к их виртуальным таблицам. Для регистров накопления это Остатки, Обороты, ОстаткиИОбороты; для регистров сведений — СрезПервых и СрезПоследних. Параметры виртуальной таблицы (период, условия отбора) указываются в скобках после её имени.

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

Какую виртуальную таблицу выбрать

Остатки

Нужны остатки на конкретную дату или момент времени. Не подходит, если требуется динамика за период.

Обороты

Нужны приход, расход или сумма движений за период. Не даёт начального и конечного сальдо.

ОстаткиИОбороты

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

СрезПоследних

Нужно актуальное значение периодического регистра сведений на дату: курсы валют, цены, ответственные лица.

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

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

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

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

После использования временные таблицы желательно уничтожать (УНИЧТОЖИТЬ ИмяТаблицы) или закрывать менеджер временных таблиц, особенно в длительных серверных процедурах: они занимают память на сервере, пока существует менеджер. В конце процедуры менеджер уничтожается автоматически, но в циклах с повторным использованием запросов это может стать проблемой.

Производительность: как не замедлить базу

Большинство проблем с производительностью запросов сводится к нескольким причинам. Первая — соединение с виртуальной таблицей без отборов в её параметрах: платформа строит остатки по всем измерениям, а потом фильтрует. Вторая — использование функций и выражений над полями в условиях соединения и отбора: ПОДСТРОКА(Наименование, 1, 5) = "Стол" отключает использование индекса.

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

Для диагностики медленных запросов используйте технологический журнал (события DBMSSQL, DBPOSTGRS с длительностью) и план запроса на стороне СУБД. Ориентируйтесь не на «кажется медленно», а на фактическое время выполнения и число логических чтений — это покажет, где теряется время: в самом запросе или в последующей обработке результата.

Типичные ошибки при работе с запросами
01
Условия в ГДЕ вместо параметров виртуальной таблицы — многократное замедление на больших регистрах
02
Запросы в цикле вместо одного запроса с соединением — линейный рост нагрузки на СУБД
03
Соединение по неиндексированным полям и выражениям — полное сканирование таблиц
04
ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL вместо РАЗНОСТЬДАТ/условия ЕСТЬ NULL — ошибки логики при неочевидных данных
05
Выгрузка миллионов строк в таблицу значений вместо обхода выборкой — расход памяти на сервере
06
Получение остатков без указания границы периода — неоднозначный результат при движениях на границе даты

Проверка результата и отладка запроса

Перед тем как использовать данные дальше, проверяйте, что запрос вернул результат: метод Результат.Пустой() показывает, есть ли строки. Для запросов, которые обязаны что-то вернуть (например, остаток товара перед списанием), пустой результат должен обрабатываться явно — сообщением пользователю или отказом в проведении, а не молчаливым пропуском.

Отлаживать текст запроса удобнее всего в консоли запросов — типовой обработке, где можно выполнить текст с реальными параметрами и увидеть результат таблицей. Консоль запросов есть в составе «Инструменты разработчика» и во многих типовых конфигурациях на БСП. Отладка «вживую» в отладчике тоже работает: точку останова ставят после Выполнить() и смотрят выгрузку результата.

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

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

Результат запроса
Норма

Результат.Пустой() = Ложь, строки соответствуют ожидаемым данным

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

Пустой результат там, где данные обязаны быть — проверяйте параметры и отборы

Типы полей
Норма

Поля имеют ожидаемые типы, NULL обработаны через ЕСТЬNULL

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

NULL в числовых полях ломает суммирование и сравнения

Время выполнения
Норма

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

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

Секунды и минуты на простом отборе — проверяйте параметры виртуальных таблиц и индексы

Итоги по иерархии
Норма

Суммы по группам сходятся с контрольными данными учёта

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

Задвоение сумм — признак лишнего соединения «один ко многим»

Частые вопросы о запросах в 1С

Чем запрос отличается от обхода объектов через выборку справочника?

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

Когда использовать ИТОГИ ПО, а когда СГРУППИРОВАТЬ ПО?

СГРУППИРОВАТЬ ПО сворачивает данные до уровня группировки — детальных строк в результате нет. ИТОГИ ПО сохраняет детальные записи и добавляет итоговые строки по группам, что нужно для отчётов с расшифровкой. Если детали не нужны, группировка быстрее и проще.

Почему запрос с РАЗРЕШЕННЫЕ работает медленнее?

Ключевое слово РАЗРЕШЕННЫЕ добавляет в запрос проверку прав доступа на уровне записей (RLS). Для пользователей без ограничений RLS накладные расходы минимальны, но если в ролях настроены сложные шаблоны ограничений, запрос может существенно замедлиться. В регламентных заданиях и служебных обработках, где права уже гарантированы логикой, РАЗРЕШЕННЫЕ обычно не используют.

Как передать в запрос таблицу значений?

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

Что делает конструкция ДЛЯ ИЗМЕНЕНИЯ?

ДЛЯ ИЗМЕНЕНИЯ устанавливает управляемую блокировку на читаемые данные до конца транзакции, чтобы другие сеансы не изменили их между чтением и записью. Применяется в транзакциях проведения, когда по прочитанным остаткам принимается решение. Вне транзакции конструкция вызовет ошибку, а чрезмерное использование повышает конкуренцию за блокировки.

Итог

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

Запросы в 1С — единственный правильный способ массового чтения данных: платформа транслирует их в SQL и возвращает результат выборкой или таблицей значений. Итоги берите из виртуальных таблиц с отборами в параметрах, избегайте запросов в цикле и соединений без индексов, а результат всегда проверяйте на пустоту и NULL-значения.