Запрос в 1С вернул не то или работает медленно: где искать причину
Содержание
Чтобы отладить запрос в 1С, остановите код точкой останова сразу после Запрос.Выполнить(), скопируйте Запрос.Текст и значения Запрос.Параметры в консоль запросов и проверяйте текст по частям. Медленный запрос разбирают отдельно: через замер производительности и технологический журнал с планом SQL.
Частое заблуждение — «запрос пустой, значит, данных нет». Чаще данные есть, а запрос их отсекает: параметр передан не того типа, граница периода не включает нужную дату, условие стоит в ГДЕ вместо параметров виртуальной таблицы. Ошибки нет, результат просто пустой — и отладчик это сам не покажет.
Консоль запросов: проверяем текст отдельно от кода
Консоль — первый инструмент для любого запроса. В ней текст запускается без обвязки модуля, и сразу видно, что вернула база.
Где взять консоль
- 📦 Стандартная обработка с диска ИТС — внешняя обработка «Консоль запросов» для управляемых форм. Открывается в режиме 1С:Предприятие через главное меню:
Файл → Открыть. - 🧩 Консоли сообщества — распространённые внешние обработки с дополнительными функциями: показ временных таблиц, время выполнения, сохранение наборов запросов.
- 🛠 Конструктор запроса в Конфигураторе — не консоль, но проверяет синтаксис и связи при закрытии окна.
Чтобы открыть внешнюю обработку, у пользователя должно быть право на интерактивное открытие внешних обработок. Если команда Файл → Открыть выдаёт отказ в доступе — это права, а не сбой консоли.
Как перенести запрос из кода в консоль
- Поставьте точку останова на строку после формирования текста (
F9). - Запустите отладку (
F5) и дойдите до точки. - Откройте окно
Вычислить выражение(Shift+F9), введитеЗапрос.Тексти скопируйте значение. - Там же посмотрите
Запрос.Параметры— это структура, в ней видны имена и значения. - Вставьте текст в консоль, на вкладке параметров задайте те же значения с теми же типами.
- Выполните запрос и сравните результат с тем, что ожидали.
💡 Если текст собирается в коде конкатенацией или через СтрЗаменить, копируйте именно итоговый Запрос.Текст из отладчика. Читать исходный модуль бесполезно: ошибка часто сидит в склейке, а не в шаблоне.
Приём «разбор по частям»
Сложный запрос на 5–10 пакетов не отлаживают целиком. Порядок такой:
- Оставьте только первый пакет, проверьте количество строк.
- Добавляйте соединения по одному. Если после очередного
ЛЕВОЕ СОЕДИНЕНИЕстрок стало больше — связь неуникальна и размножает записи. - Условия
ГДЕвключайте последними и тоже по одному.
Так за несколько запусков находится строка, после которой результат «поехал».
Отладка запроса прямо в модуле
Иногда в консоли всё работает, а в коде — нет. Значит, разница во входных данных: в параметрах, в менеджере временных таблиц, в правах пользователя.
Что смотреть в окне «Вычислить выражение»
| Выражение | Что показывает |
|---|---|
Запрос.Текст | итоговый текст, который ушёл в базу |
Запрос.Параметры | все переданные параметры и их значения |
Результат.Выгрузить() | таблица значений с результатом |
Результат.Пустой() | Истина, если строк нет |
ТипЗнч(Запрос.Параметры.Организация) | фактический тип параметра |
Таблицу значений из Выгрузить() можно раскрыть в окне просмотра значения отладчика и пролистать строки.
Временные таблицы и пакеты
Пакет с ПОМЕСТИТЬ возвращает результат только последнего запроса. Промежуточные таблицы так не видны. Есть два способа их посмотреть.
Способ 1. Выполнить пакет с промежуточными данными.
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Период", КонецДня(ДатаОтчета));
// Массив результатов: по одному на каждый запрос пакета
Результаты = Запрос.ВыполнитьПакетСПромежуточнымиДанными();
Для Индекс = 0 По Результаты.ВГраница() Цикл
Таблица = Результаты[Индекс].Выгрузить();
Сообщить(СтрШаблон("Пакет %1: строк %2", Индекс + 1, Таблица.Количество()));
КонецЦикла;
Метод возвращает массив, в котором есть данные и запросов с ПОМЕСТИТЬ. Так сразу видно, на каком пакете строк стало ноль.
Способ 2. Заглянуть в менеджер временных таблиц.
После выполнения в отладчике вычислите Запрос.МенеджерВременныхТаблиц.Таблицы. Это коллекция, у каждого элемента есть метод ПолучитьДанные(), который возвращает результат запроса по содержимому таблицы.
Используйте ВыполнитьПакетСПромежуточнымиДанными() только для отладки. В рабочем коде он тратит лишнюю память на результаты, которые никто не читает.
Отладка на сервере
В файловой базе отладка работает сразу. В клиент-серверной базе код на сервере остановится на точке, только если на сервере 1С включена отладка. Без этого точки в серверных процедурах просто пропускаются.
Не включайте отладку на рабочем сервере в часы работы пользователей без согласования: остановка на точке держит сеанс и может задерживать чужие операции. Лучше развернуть копию базы и отлаживать там.
Виртуальные таблицы и срезы: где теряются строки
Больше всего «тихих» ошибок дают виртуальные таблицы регистров: Остатки, Обороты, ОстаткиИОбороты, СрезПоследних, СрезПервых.
Условие в параметрах или в ГДЕ
Сравните два варианта:
// Правильно: отбор внутри виртуальной таблицы
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки
// Медленнее и иногда с другим результатом: отбор после расчёта
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период) КАК Остатки
ГДЕ
Остатки.Склад = &Склад
Для остатков по одному измерению оба запроса вернут одно и то же. Но во втором случае платформа сначала посчитает остатки по всем складам, а потом отбросит лишнее. Для СрезПоследних разница бывает и в результате: отбор в ГДЕ применяется к уже выбранной последней записи, а отбор в параметрах — до выбора.
Пример: цена номенклатуры записана по двум типам цен. СрезПоследних(&Дата) с отбором ГДЕ ТипЦен = &Тип вернёт строку, только если по этому типу запись есть в срезе. Ставьте отбор по измерениям в параметры таблицы.
Граница периода
- 📅
Остатки(&Период)с датой без времени даёт остатки на начало этих суток. Документы, проведённые днём, не войдут. - ✅ Передавайте
КонецДня(Дата)илиНовый Граница(Дата, ВидГраницы.Включая). - 🧾 Чтобы получить остатки «до документа», передавайте
МоментВремени()документа — тогда движения самого документа не учтутся. - 🔁 У
ОстаткиИОборотыпроверьте параметр периодичности: при неверном значении строк будет больше, чем ожидали.
Пустые поля после соединения
Если таблица присоединена левым соединением и записи нет, поле вернётся как NULL, а не как ноль. Сложение NULL с числом даёт NULL. Оборачивайте такие поля в ЕСТЬNULL(Остатки.КоличествоОстаток, 0).
Синтаксические ошибки: как читать сообщение платформы
Синтаксическая ошибка в запросе всплывает в момент Выполнить(). В тексте исключения есть координаты: {(12, 5)}: — строка 12 и колонка 5 текста запроса, а не модуля.
Как быстро найти место
- Скопируйте
Запрос.Текстиз отладчика. - Вставьте в консоль или любой редактор с нумерацией строк.
- Отсчитайте строку из сообщения. Если текст склеен из кусков, номер будет отличаться от строки в модуле.
Частые причины
| Симптом в сообщении | Что проверить |
|---|---|
| Синтаксическая ошибка у слова | пропущенная запятая в списке полей, лишняя запятая перед ИЗ |
| Поле не найдено | опечатка в имени реквизита или псевдониме таблицы |
| Таблица не найдена | имя объекта метаданных; в запросе пишут Справочник.Склады, а не Справочники.Склады, как в модуле |
| Неоднозначное поле | одно имя поля есть в двух таблицах — укажите псевдоним |
| Ожидается выражение | пустой кусок после СтрЗаменить или условие без правой части |
💡 Самый быстрый способ проверить синтаксис — открыть текст в конструкторе запроса. В Конфигураторе поставьте курсор внутрь строки с текстом запроса и вызовите конструктор из контекстного меню. Если текст некорректен, конструктор откажется его разобрать и покажет причину.
Текст, собранный динамически
Ошибки склейки выглядят так: два куска без пробела (...Склад = &СкладИ Номенклатура...), лишнее И в начале условия, незакрытая скобка. Добавляйте пробел или перенос строки в начале каждого подставляемого фрагмента. Ещё надёжнее — держать все условия в тексте и включать их параметрами, а не склейкой.
Типы данных и параметры: ошибки без ошибок
Платформа не ругается, если параметр не того типа. Запрос просто не находит совпадений.
Что проверить в первую очередь
- 🔤 Строка вместо ссылки. Передали
"Основной склад"в параметр, который сравнивается со ссылкой. Результат пустой. ПроверьтеТипЗнч()в отладчике. - 🗓 Дата без времени. См. раздел о границах периода выше.
- 📋 Массив для
В (&Список). Параметр должен быть массивом, списком значений или таблицей. Пустой массив даёт пустой результат, а не «все значения». - 🔗 Пустая ссылка и
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. Это ограничения доступа на уровне записей. Проверьте, выполняется ли запрос в привилегированном режиме и нужен ли он там.
- 🗃 Разделители. В базе с разделением данных запрос видит только текущую область.
- 🕒 Кэш и повторное использование. Если значение берётся из модуля с повторным использованием возвращаемых значений, отладка увидит старый результат до конца сеанса.
- 🧮 Итоги регистров. Если остатки в
Остаткирасходятся с суммой движений, проверьте, не отключены ли итоги и актуальны ли они. Пересчёт итогов выполняйте вне рабочего времени.
Частые вопросы
Можно ли отладить запрос без Конфигуратора?
Почему конструктор запроса стирает мои комментарии?
// и ручное форматирование. Держите копию текста, если она важна.Как отладить запрос отчёта на СКД?
Почему в консоли запрос быстрый, а в коде медленный?
Где взять текст SQL, в который превратился запрос 1С?
DBMSSQL для клиент-серверной базы. Имена таблиц там служебные; сопоставить их с объектами метаданных помогает функция ПолучитьСтруктуруХраненияБазыДанных().