Запрос в 1С вернул не то или работает медленно: где искать причину

· 10 мин

Содержание

Чтобы отладить запрос в 1С, остановите код точкой останова сразу после Запрос.Выполнить(), скопируйте Запрос.Текст и значения Запрос.Параметры в консоль запросов и проверяйте текст по частям. Медленный запрос разбирают отдельно: через замер производительности и технологический журнал с планом SQL.

Частое заблуждение — «запрос пустой, значит, данных нет». Чаще данные есть, а запрос их отсекает: параметр передан не того типа, граница периода не включает нужную дату, условие стоит в ГДЕ вместо параметров виртуальной таблицы. Ошибки нет, результат просто пустой — и отладчик это сам не покажет.

Консоль запросов: проверяем текст отдельно от кода

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

Где взять консоль

  • 📦 Стандартная обработка с диска ИТС — внешняя обработка «Консоль запросов» для управляемых форм. Открывается в режиме 1С:Предприятие через главное меню: Файл → Открыть.
  • 🧩 Консоли сообщества — распространённые внешние обработки с дополнительными функциями: показ временных таблиц, время выполнения, сохранение наборов запросов.
  • 🛠 Конструктор запроса в Конфигураторе — не консоль, но проверяет синтаксис и связи при закрытии окна.

Чтобы открыть внешнюю обработку, у пользователя должно быть право на интерактивное открытие внешних обработок. Если команда Файл → Открыть выдаёт отказ в доступе — это права, а не сбой консоли.

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

  1. Поставьте точку останова на строку после формирования текста (F9).
  2. Запустите отладку (F5) и дойдите до точки.
  3. Откройте окно Вычислить выражение (Shift+F9), введите Запрос.Текст и скопируйте значение.
  4. Там же посмотрите Запрос.Параметры — это структура, в ней видны имена и значения.
  5. Вставьте текст в консоль, на вкладке параметров задайте те же значения с теми же типами.
  6. Выполните запрос и сравните результат с тем, что ожидали.

💡 Если текст собирается в коде конкатенацией или через СтрЗаменить, копируйте именно итоговый Запрос.Текст из отладчика. Читать исходный модуль бесполезно: ошибка часто сидит в склейке, а не в шаблоне.

Приём «разбор по частям»

Сложный запрос на 5–10 пакетов не отлаживают целиком. Порядок такой:

  1. Оставьте только первый пакет, проверьте количество строк.
  2. Добавляйте соединения по одному. Если после очередного ЛЕВОЕ СОЕДИНЕНИЕ строк стало больше — связь неуникальна и размножает записи.
  3. Условия ГДЕ включайте последними и тоже по одному.

Так за несколько запусков находится строка, после которой результат «поехал».

Отладка запроса прямо в модуле

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

Что смотреть в окне «Вычислить выражение»

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

Таблицу значений из Выгрузить() можно раскрыть в окне просмотра значения отладчика и пролистать строки.

Временные таблицы и пакеты

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

Способ 1. Выполнить пакет с промежуточными данными.

Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Период", КонецДня(ДатаОтчета));

// Массив результатов: по одному на каждый запрос пакета
Результаты = Запрос.ВыполнитьПакетСПромежуточнымиДанными();
Для Индекс = 0 По Результаты.ВГраница() Цикл
	Таблица = Результаты[Индекс].Выгрузить();
	Сообщить(СтрШаблон("Пакет %1: строк %2", Индекс + 1, Таблица.Количество()));
КонецЦикла;

Метод возвращает массив, в котором есть данные и запросов с ПОМЕСТИТЬ. Так сразу видно, на каком пакете строк стало ноль.

Способ 2. Заглянуть в менеджер временных таблиц.

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

Используйте ВыполнитьПакетСПромежуточнымиДанными() только для отладки. В рабочем коде он тратит лишнюю память на результаты, которые никто не читает.

Отладка на сервере

В файловой базе отладка работает сразу. В клиент-серверной базе код на сервере остановится на точке, только если на сервере 1С включена отладка. Без этого точки в серверных процедурах просто пропускаются.

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

Виртуальные таблицы и срезы: где теряются строки

Больше всего «тихих» ошибок дают виртуальные таблицы регистров: Остатки, Обороты, ОстаткиИОбороты, СрезПоследних, СрезПервых.

Условие в параметрах или в ГДЕ

Сравните два варианта:

// Правильно: отбор внутри виртуальной таблицы
ВЫБРАТЬ
	Остатки.Номенклатура,
	Остатки.КоличествоОстаток
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки

// Медленнее и иногда с другим результатом: отбор после расчёта
ВЫБРАТЬ
	Остатки.Номенклатура,
	Остатки.КоличествоОстаток
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(&Период) КАК Остатки
ГДЕ
	Остатки.Склад = &Склад

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

Пример: цена номенклатуры записана по двум типам цен. СрезПоследних(&Дата) с отбором ГДЕ ТипЦен = &Тип вернёт строку, только если по этому типу запись есть в срезе. Ставьте отбор по измерениям в параметры таблицы.

Граница периода

  • 📅 Остатки(&Период) с датой без времени даёт остатки на начало этих суток. Документы, проведённые днём, не войдут.
  • ✅ Передавайте КонецДня(Дата) или Новый Граница(Дата, ВидГраницы.Включая).
  • 🧾 Чтобы получить остатки «до документа», передавайте МоментВремени() документа — тогда движения самого документа не учтутся.
  • 🔁 У ОстаткиИОбороты проверьте параметр периодичности: при неверном значении строк будет больше, чем ожидали.

Пустые поля после соединения

Если таблица присоединена левым соединением и записи нет, поле вернётся как NULL, а не как ноль. Сложение NULL с числом даёт NULL. Оборачивайте такие поля в ЕСТЬNULL(Остатки.КоличествоОстаток, 0).

Синтаксические ошибки: как читать сообщение платформы

Синтаксическая ошибка в запросе всплывает в момент Выполнить(). В тексте исключения есть координаты: {(12, 5)}: — строка 12 и колонка 5 текста запроса, а не модуля.

Как быстро найти место

  1. Скопируйте Запрос.Текст из отладчика.
  2. Вставьте в консоль или любой редактор с нумерацией строк.
  3. Отсчитайте строку из сообщения. Если текст склеен из кусков, номер будет отличаться от строки в модуле.

Частые причины

Симптом в сообщенииЧто проверить
Синтаксическая ошибка у словапропущенная запятая в списке полей, лишняя запятая перед ИЗ
Поле не найденоопечатка в имени реквизита или псевдониме таблицы
Таблица не найденаимя объекта метаданных; в запросе пишут Справочник.Склады, а не Справочники.Склады, как в модуле
Неоднозначное полеодно имя поля есть в двух таблицах — укажите псевдоним
Ожидается выражениепустой кусок после СтрЗаменить или условие без правой части

💡 Самый быстрый способ проверить синтаксис — открыть текст в конструкторе запроса. В Конфигураторе поставьте курсор внутрь строки с текстом запроса и вызовите конструктор из контекстного меню. Если текст некорректен, конструктор откажется его разобрать и покажет причину.

Текст, собранный динамически

Ошибки склейки выглядят так: два куска без пробела (...Склад = &СкладИ Номенклатура...), лишнее И в начале условия, незакрытая скобка. Добавляйте пробел или перенос строки в начале каждого подставляемого фрагмента. Ещё надёжнее — держать все условия в тексте и включать их параметрами, а не склейкой.

Типы данных и параметры: ошибки без ошибок

Платформа не ругается, если параметр не того типа. Запрос просто не находит совпадений.

Что проверить в первую очередь

  • 🔤 Строка вместо ссылки. Передали "Основной склад" в параметр, который сравнивается со ссылкой. Результат пустой. Проверьте ТипЗнч() в отладчике.
  • 🗓 Дата без времени. См. раздел о границах периода выше.
  • 📋 Массив для В (&Список). Параметр должен быть массивом, списком значений или таблицей. Пустой массив даёт пустой результат, а не «все значения».
  • 🔗 Пустая ссылка и NULL. Это разные значения. Пустой реквизит в справочнике — пустая ссылка; отсутствующая запись в левом соединении — NULL. Условие = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка) не поймает NULL.

Составные типы и строки неограниченной длины

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

В консоли типы задаются вручную

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

Медленный запрос: замер производительности и план выполнения

Если запрос возвращает правильные данные, но выполняется 20 секунд вместо одной, нужны другие инструменты.

Шаг 1. Замер производительности

В Конфигураторе запустите отладку, включите замер через меню Отладка → Замер производительности и выполните действие в 1С:Предприятии. После остановки замера увидите строки модуля с временем и числом вызовов. Если основное время — на строке Запрос.Выполнить(), тормозит сам запрос, а не код вокруг.

💡 Строка с Выполнить() внутри цикла и 1 000 вызовов — типичная находка. Вынесите запрос из цикла: получите данные одним запросом по массиву и ищите в таблице значений.

Шаг 2. Технологический журнал и план SQL

Чтобы увидеть, что СУБД реально делает с запросом, включают технологический журнал. Файл настройки logcfg.xml кладут в каталог conf сервера 1С. Минимальный пример для записи долгих запросов к СУБД:

<config xmlns="http://v8.1c.ru/v8/tech-log">
	<log location="C:\1C_TechLog" history="2">
		<event>
			<eq property="name" value="DBMSSQL"/>
			<gt property="duration" value="1000000"/>
		</event>
		<property name="all"/>
	</log>
	<plansql/>
</config>

Элемент <plansql/> добавляет в события план выполнения запроса. Длительность в 8.3 указывается в микросекундах: 1000000 — это запросы дольше одной секунды.

Техжурнал с планами нагружает сервер и быстро занимает диск. Включайте его на ограниченное время, с отбором по длительности или по базе, и удаляйте logcfg.xml после сбора. В событии будет текст запроса в терминах СУБД — имена таблиц вида _Reference45.

Что обычно находится в плане

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

Для файловой базы планов SQL нет. Там ориентируйтесь на замер производительности и время выполнения в консоли.

Если ничего не нашли: что ещё проверить

  • 🔐 Права и RLS. Под администратором запрос возвращает 100 строк, под бухгалтером — 40. Это ограничения доступа на уровне записей. Проверьте, выполняется ли запрос в привилегированном режиме и нужен ли он там.
  • 🗃 Разделители. В базе с разделением данных запрос видит только текущую область.
  • 🕒 Кэш и повторное использование. Если значение берётся из модуля с повторным использованием возвращаемых значений, отладка увидит старый результат до конца сеанса.
  • 🧮 Итоги регистров. Если остатки в Остатки расходятся с суммой движений, проверьте, не отключены ли итоги и актуальны ли они. Пересчёт итогов выполняйте вне рабочего времени.
Запрос вернул не то: короткая проверка
Выполнено: 0 / 6

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

Можно ли отладить запрос без Конфигуратора?
Да. Достаточно консоли запросов в режиме 1С:Предприятие и права открывать внешние обработки. Текст запроса берут из модуля или из описания отчёта.
Почему конструктор запроса стирает мои комментарии?
Конструктор пересобирает текст заново и не сохраняет комментарии // и ручное форматирование. Держите копию текста, если она важна.
Как отладить запрос отчёта на СКД?
Текст набора данных скопируйте из схемы компоновки в консоль. Учтите, что СКД сама добавляет отборы и параметры из настроек отчёта, поэтому сравнивайте результат с теми же настройками.
Почему в консоли запрос быстрый, а в коде медленный?
Обычно он вызывается в цикле или с другими параметрами. Второй частый случай — в коде включены ограничения доступа на уровне записей, а в консоли вы работаете под полными правами.
Где взять текст SQL, в который превратился запрос 1С?
В технологическом журнале, в событии DBMSSQL для клиент-серверной базы. Имена таблиц там служебные; сопоставить их с объектами метаданных помогает функция ПолучитьСтруктуруХраненияБазыДанных().