Почему дополнительная обработка по расписанию не выполняется или падает по таймауту, и как оптимизировать запрос?

Программист 1С v8.3 (Управляемые формы) 1С:Розница Торговля и дистрибуция
← На главную

В практике разработки и администрирования 1С часто встречаются ситуации, когда регламентное задание или дополнительная обработка, запускаемая по расписанию, работает некорректно. Особенно запутанным случай становится, когда под полными правами (Администратор) все кажется рабочим, а под пользователем (например, Кассир) задание "буксует".

Давайте подробно разберем реальный кейс: обработка должна выгружать чеки каждые несколько минут, но фактически ничего не происходит. Мы пройдем путь от диагностики настроек расписания до глубокой оптимизации запроса на языке 1С.

Этап 1: Диагностика проблемы и анализ Журнала регистрации

В рассматриваемой ситуации мы имеем следующую вводную: есть дополнительная обработка в конфигурации "1С:Розница 2.3". Настроено расписание (каждые 300 секунд) и назначен ответственный пользователь. Однако результат (файл выгрузки) не появляется.

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

Почему так происходит? Давайте проанализируем настройки регламентного задания:

  1. Расписание: Запуск частый (раз в 2-5 минут).
  2. Настройка завершения: Указано "Завершать через 30 сек".

Именно второй пункт является критическим. Если код обработки выполняется дольше 30 секунд, платформа принудительно прерывает фоновое задание. В зависимости от настроек технологического журнала и версии платформы, такое прерывание ("убийство" процесса) может не успеть записать красивый стек ошибки в стандартный журнал регистрации, либо транзакция откатывается полностью, и мы не видим следов деятельности.

В нашем случае выяснилось, что простейшая выгрузка чеков за текущий день выполнялась около 3 минут. Естественно, с настройкой "завершать через 30 секунд" задание никогда не доходило до конца.

Этап 2: Анализ "тяжелого" запроса

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

Исходный текст запроса:


Запрос = новый Запрос("ВЫБРАТЬ
      ""1"" КАК Азс,
      ЧекККМТовары.Номенклатура.Наименование КАК Номенклатура,
      ЧекККМТовары.Количество КАК Количество,
      ЧекККМТовары.Сумма КАК Сумма,
      ЧекККМТовары.Ссылка.Дата КАК Дата
ИЗ
      Документ.ЧекККМ.Товары КАК ЧекККМТовары
ГДЕ
      ЧекККМТовары.Ссылка.Проведен = Истина
      И НАЧАЛОПЕРИОДА(ЧекККМТовары.Ссылка.Дата, ДЕНЬ) = &Дата
УПОРЯДОЧИТЬ ПО
      Дата");

Запрос.УстановитьПараметр("Дата", НачалоДня(ТекущаяДата()));

Давайте разберем, почему этот запрос, возвращающий всего пару строк результата, работает минуты. Здесь допущены две грубые ошибки, критично влияющие на производительность SQL-сервера.

Ошибка 1: Использование функций над полями в условии ГДЕ

Обратите внимание на конструкцию:

НАЧАЛОПЕРИОДА(ЧекККМТовары.Ссылка.Дата, ДЕНЬ) = &Дата

Когда мы применяем функцию (в данном случае НАЧАЛОПЕРИОДА) к полю таблицы базы данных (Дата), SQL-оптимизатор не может использовать индекс по этому полю. Ему приходится выполнять сканирование всей таблицы (Table Scan или Index Scan), вычислять значение функции для каждой записи и только потом сравнивать с параметром. Если в базе миллионы чеков, это занимает огромное время.

Ошибка 2: Обращение к полям "через точку" (Неявные соединения)

Запрос строится к табличной части Документ.ЧекККМ.Товары. Однако в условии отбора мы обращаемся к реквизитам шапки документа:

Каждое обращение через Ссылка.Поле при выборе из табличной части создает неявное левое соединение (Left Join) с таблицей шапки документа. В сочетании с первой ошибкой (невозможность использовать индекс по дате), СУБД вынуждена соединять огромные массивы данных, а затем фильтровать их неоптимальным способом.

Этап 3: Оптимизация и правильное решение

Чтобы задание выполнялось мгновенно и укладывалось в отведенные 30 секунд, нам нужно переписать запрос так, чтобы он использовал индексы. Для этого мы должны избавиться от функций в условиях и оптимизировать соединения.

Рассмотрим правильный подход:

  1. Вместо равенства даты с точностью до дня используем интервал (диапазон) дат.
  2. Явно задаем начало и конец периода.

Вот как должен выглядеть оптимизированный код:


// Определяем границы периода заранее
НачПериода = НачалоДня(ТекущаяДата());
КонПериода = КонецДня(ТекущаяДата());

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	""1"" КАК Азс,
|	ЧекККМТовары.Номенклатура.Наименование КАК Номенклатура,
|	ЧекККМТовары.Количество КАК Количество,
|	ЧекККМТовары.Сумма КАК Сумма,
|	ЧекККМ.Дата КАК Дата
|ИЗ
|	Документ.ЧекККМ.Товары КАК ЧекККМТовары
|		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЧекККМ КАК ЧекККМ
|		ПО ЧекККМТовары.Ссылка = ЧекККМ.Ссылка
|ГДЕ
|	ЧекККМ.Дата МЕЖДУ &НачДата И &КонДата
|	И ЧекККМ.Проведен = ИСТИНА
|
|УПОРЯДОЧИТЬ ПО
|	Дата";

Запрос.УстановитьПараметр("НачДата", НачПериода);
Запрос.УстановитьПараметр("КонДата", КонПериода);

Почему этот вариант работает быстрее?

Примечание: Еще более производительный вариант (особенно на очень больших базах) — сначала выбрать ссылки на документы во временную таблицу по отбору дат, а затем соединить эту временную таблицу с табличной частью товаров. Но в рамках задачи "выгрузка за один день" предложенного выше варианта с МЕЖДУ будет более чем достаточно.

Этап 4: Дополнительные настройки для регламентных заданий

После оптимизации кода не забудьте проверить окружение, так как мы говорим о запуске "на сервере" под определенным пользователем.

  1. Файловая система: Убедитесь, что путь к файлу выгрузки доступен пользователю, от имени которого запущен сервер 1С (USR1CV8), а не только вашему локальному пользователю. Использование сетевых путей (UNC) типа \\Server\Share\File.txt предпочтительнее локальных дисков C:\....
  2. Безопасный режим: В "1С:Розница" и других современных конфигурациях дополнительные обработки по умолчанию запускаются в безопасном режиме. Это запрещает запись файлов и доступ в интернет.

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

  3. Пользователь регламентного задания: Если задание запускается под "Кассиром", у этого пользователя должны быть права не только на чтение чеков, но и на "Вывод информации" (для записи файлов), а также на запуск внешних обработок.

Заключение

Если ваша обработка по расписанию "молчит" и не оставляет следов в журнале:

  1. Проверьте, не стоит ли слишком жесткое ограничение времени выполнения (таймаут) в настройках задания.
  2. Проанализируйте код на предмет производительности. Использование функций (НАЧАЛОПЕРИОДА, ГОД, МЕСЯЦ) в условиях запроса — главная причина замедления.
  3. Замените проверки на равенство периодов на диапазоны дат (МЕЖДУ).
  4. Убедитесь, что сервер имеет физический доступ к папке для записи результата.
← На главную