Как устранить зависание при распределении загрузки мастеров в 1С:Управление сервисным центром

Программист 1С v8.3 (Управляемые формы) Управленческий учет Сфера услуг, туризм и социальный сектор
← На главную

В процессе работы с отраслевым решением «1С:Управление сервисным центром» (УСЦ) пользователи часто сталкиваются с критической проблемой: при попытке открыть обработку «Распределение загрузки мастеров» (раздел «Ремонт и обслуживание» -> «Планирование загрузки») сеанс работы системы полностью зависает. Единственным выходом остается принудительное завершение процесса 1cv8.exe через диспетчер задач. Это парализует работу диспетчеров и мастеров сервисного центра.

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

---

Симптомы зависания и поведение платформы 1С

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

  1. Зависание происходит не только на этапе выполнения самого запроса, но и при обходе его результата с помощью метода ПоВыездПрием.Следующий().
  2. Даже простейшие строки кода очистки данных управляемой формы, такие как лСписокДокументов = РеквизитФормыВЗначение("НовыйСписокДокументов") и лСписокДокументов.Строки.Очистить(), могут выполняться по 10–15 минут или вызывать полное зависание потока.

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

---

Причина №1. Критическая ошибка в тексте запроса (Декартово произведение)

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


ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаданиеНаРаботу.Работы КАК ЗаданиеНаРаботуРаботы
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаданиеНаРаботу.Работы КАК ЗаданиеНаРаботуРаботыДлительностьЭтапа
    ПО ЗаданиеНаРаботуРаботы.Ссылка = ЗаданиеНаРаботуРаботыДлительностьЭтапа.Ссылка

Здесь допущена грубейшая ошибка проектирования структуры БД. Табличная часть Работы документа ЗаданиеНаРаботу соединяется сама с собой только по полю Ссылка. При этом связи по номеру строки или уникальному идентификатору строки (этапа) нет.

Что это означает на практике?
Это классическое декартово произведение (Cartesian Product) в рамках каждого конкретного документа. Если в табличной части «Работы» документа содержится 5 строк, то в результате такого соединения СУБД сгенерирует 25 строк ($5 \times 5$). Если в документе 20 строк — мы получим уже 400 строк. При наличии сотен и тысяч документов в базе данных итоговая выборка раздувается до миллионов дублирующихся записей.

Именно поэтому ограничение выборки с помощью конструкции ПЕРВЫЕ 100 не помогает: СУБД тратит колоссальные ресурсы и дисковое пространство (tempdb в MS SQL) на перемножение таблиц во временной памяти еще до того, как применит финальное ограничение.

---

Причина №2. Неоптимальная работа с контекстом управляемой формы

Теперь разберем, почему зависает строка лСписокДокументов = РеквизитФормыВЗначение("НовыйСписокДокументов").

Метод РеквизитФормыВЗначение производит полную сериализацию и конвертацию данных из структуры управляемой формы в объектные типы данных платформы (в данном случае — в ДеревоЗначений). Если дерево формы ранее уже было заполнено тысячами элементов из-за некорректного запроса, платформа начинает монопольно пересчитывать индексы, связи и элементы управления формы на сервере. Это вызывает резкий скачок потребления оперативной памяти процессом rphost и визуальное зависание.

Аналогично ведет себя и метод ПоВыездПрием.Следующий(). При использовании обхода ОбходРезультатаЗапроса.ПоГруппировкам платформа 1С строит иерархическое дерево в оперативной памяти сервера приложений. Миллионы дублирующихся строк из декартова произведения мгновенно перегружают стек вызовов платформы.

---

Причина №3. Отсутствие необходимых индексов в СУБД

В тексте запроса активно используются левые соединения (LEFT JOIN) с документами СЦентр_ОтчетПоРаботеУКлиента, СЦентр_ВозвратИзРемонта и ЗаказПокупателя по реквизиту ДокументОснование (или СЦентр_ДокументОснование).

Если для этих реквизитов в свойствах метаданных конфигурации не установлено свойство «Индексировать», СУБД не может выполнить быстрый поиск по индексу (Index Seek) и переходит к полному сканированию таблиц (Table Scan). На реальных базах объемом более 5–10 Гб это приводит к катастрофическому падению скорости выполнения любых запросов.

---

Пошаговое руководство по решению проблемы

Для восстановления работоспособности обработки «Распределение загрузки мастеров» выполним три последовательных шага.

Шаг 1. Исправление и оптимизация запроса

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

Рассмотрим более производительный вариант получения длительности этапа без использования избыточных соединений:


// Вместо двойного соединения ТЧ "Работы" выберем данные один раз и сгруппируем их
ВЫБРАТЬ
    ВыездПрием.Ссылка КАК ДокументПриемВыезд,
    ЗаданиеНаРаботуРаботы.Ссылка.ВидЭтапа КАК ТекВидЭтапа,
    СУММА(ВЫРАЗИТЬ(РАЗНОСТЬДАТ(ЗаданиеНаРаботуРаботы.ДатаНачала, ЗаданиеНаРаботуРаботы.ДатаОкончания, МИНУТА) / 60 КАК ЧИСЛО(15, 2))) КАК ДлительностьЧасовТекущегоЭтапа
ПОМЕСТИТЬ ВременнаяТаблицаДлительности
ИЗ
    ЖурналДокументов.СЦентр_ДокументыПоРемонтуИОбслуживанию КАК ВыездПрием
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаданиеНаРаботу.Работы КАК ЗаданиеНаРаботуРаботы
    ПО ВыездПрием.Ссылка = ЗаданиеНаРаботуРаботы.Ссылка.ДокументОснование
ГДЕ
    ЗаданиеНаРаботуРаботы.Ссылка.Состояние = ЗНАЧЕНИЕ(Справочник.СостоянияСобытий.Запланировано)
СГРУППИРОВАТЬ ПО
    ВыездПрием.Ссылка,
    ЗаданиеНаРаботуРаботы.Ссылка.ВидЭтапа

Замените проблемный участок в вашей обработке аналогичным пакетом. Это исключит умножение строк и снизит нагрузку на СУБД в сотни раз.

Шаг 2. Оптимизация работы с управляемой формой

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

  1. Очищайте коллекцию формы напрямую, без её преобразования в прикладной объект.
  2. Выгружайте результат запроса в обычную таблицу или дерево значений на сервере, а затем быстро транслируйте данные обратно в форму с помощью метода ЗначениеВДанныеФормы.

Посмотрим на пример правильной реализации очистки и заполнения:


// Избегаем тяжелого вызова лСписокДокументов = РеквизитФормыВЗначение(...)
// Очищаем элементы дерева непосредственно на форме:
НовыйСписокДокументов.ПолучитьЭлементы().Очистить();

// Получаем результат запроса в плоскую таблицу или дерево на сервере
ТаблицаРезультата = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

// Быстро и безопасно переносим данные в реквизит формы
ЗначениеВДанныеФормы(ТаблицаРезультата, НовыйСписокДокументов);

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

Шаг 3. Индексация полей связи в метаданных

Откройте конфигуратор и найдите документы, которые участвуют в левых соединениях запроса (СЦентр_ОтчетПоРаботеУКлиента, СЦентр_ВозвратИзРемонта, ЗаказПокупателя).

Для реквизита ДокументОснование (или его отраслевого аналога) в свойствах установите значение индексирования:

После внесения изменений в структуру метаданных обязательно выполните обслуживание базы данных. Для этого в режиме «Конфигуратор» перейдите в меню «Администрирование» -> «Тестирование и исправление», отметьте пункты «Реиндексация таблиц» и «Обновление статистики» и запустите процесс.

---

Резюме

Причиной «мертвого» зависания обработки распределения загрузки мастеров в УСЦ является совокупность ошибок в коде:

Применив предложенные шаги по исправлению запроса, оптимизации работы с коллекциями формы и индексации СУБД, вы добьетесь мгновенного открытия формы распределения загрузки даже на сильно нагруженных информационных базах.

← На главную