При разработке и сопровождении конфигураций на платформе «1С:Предприятие» одной из наиболее частых причин снижения производительности интерфейса является некорректная работа с динамическими списками и табличными полями. Классический пример такой ошибки — размещение запросов к базе данных внутри обработчика события ПриВыводеСтроки. В этой статье мы подробно разберем, как ведет себя система, если форма с таким «тяжелым» кодом открыта, но свернута, влияет ли это на общую производительность 1С, и как правильно оптимизировать этот узел, чтобы система работала быстро.
Прежде чем анализировать влияние свернутой формы, давайте вспомним физику процесса работы табличного поля в толстом клиенте 1С (особенно актуально для версий 8.2 и обычных форм 8.3). Событие ПриВыводеСтроки вызывается платформой в тот момент, когда строка таблицы визуально отрисовывается на экране монитора пользователя. Если на экране помещается, например, 20 строк, то при открытии формы или при ее прокрутке (скроллинге) это событие выполнится ровно 20 раз — индивидуально для каждой строки.
Если внутри этого обработчика написать запрос к базе данных (например, для получения остатка товара, актуальной цены или статуса взаиморасчетов), то система выполнит 20 отдельных обращений к СУБД. Это классическая проблема «N+1 запроса». На одну открытую форму мы получаем лавинообразную нагрузку.
А теперь ответим на главный вопрос автора: если эта форма открыта, но свернута (минимизирована), продолжают ли выполняться эти запросы и тормозит ли 1С в целом?
Проанализируем поведение платформы 1С при сворачивании формы. Провести этот эксперимент может каждый разработчик с помощью обычного отладчика:
ПриВыводеСтроки.Результат: при свернутом окне точка останова больше не срабатывает. Это происходит потому, что вызов события ПриВыводеСтроки жестко привязан к графической отрисовке элементов операционной системой. Если окно свернуто, перерисовка элементов интерфейса (компонентов формы) не требуется, а значит, платформа не инициирует выполнение кода внутри этого обработчика. Следовательно, в свернутом состоянии тяжелые запросы из этой процедуры напрямую не выполняются.
Однако расслабляться рано. Существуют важные нюансы, из-за которых эта форма все равно продолжает вредить производительности всей системы.
Даже если запросы в ПриВыводеСтроки временно «молчат», открытая свернутая форма продолжает оказывать негативное влияние на систему по следующим причинам:
1. Механизм автообновления динамического списка. Если для динамического списка включено свойство Автообновление, платформа будет с определенной периодичностью отправлять запросы к СУБД для проверки изменений в базе данных. Сам по себе этот фоновый запрос работает оптимизированно, но если текст основного запроса списка перегружен, это создает постоянный фоновый шум на сервере СУБД.
2. Лавинообразный всплеск нагрузки при разворачивании. Как только пользователь развернет или просто активирует свернутое окно, операционная система потребует мгновенно перерисовать интерфейс. Платформа тут же выполнит обработчик ПриВыводеСтроки для всех видимых на экране записей. В этот момент пользователь гарантированно получит ощутимый «фриз» (зависание) интерфейса на несколько секунд.
3. Влияние на общую производительность СУБД (проблема для всех пользователей). Если один разработчик или менеджер свернул форму, нагрузка у него пропала. Но если эту форму открыли (и не свернули) еще 10–15 пользователей в локальной сети, они начинают активно прокручивать список. В этот момент сервер СУБД (например, MS SQL Server или PostgreSQL) буквально захлебывается тысячами мелких, однотипных запросов. Из-за перегрузки процессора сервера или блокировок таблиц тормозить начинает вся база данных целиком. В итоге у других пользователей начинают «висеть» совершенно другие документы и справочники, никак не связанные с этой формой.
4. Однопоточность клиентского приложения в толстом клиенте. В режиме толстого клиента 1С 8.2 выполнение кода происходит преимущественно в одном потоке. Любое случайное событие перерисовки интерфейса (например, поверх свернутого окна протащили другое окно или изменилось разрешение экрана) может заставить систему попытаться обновить элементы формы, что приведет к моментальной потере отзывчивости всего сеанса пользователя.
Чтобы точно определить, какой именно кусок кода вызывает замедление работы формы, мы рекомендуем использовать встроенные инструменты отладки 1С. Рассмотрим по шагам, как запустить замер производительности:
В проблемной форме вы увидите, что практически 95-99% процессорного времени тратится внутри процедуры ПриВыводеСтроки на строках создания и выполнения запросов. Это неопровержимое доказательство того, что данный участок кода требует немедленного рефакторинга.
Наличие запросов в цикле отрисовки строк считается грубейшей ошибкой проектирования (за это сразу ставят неудовлетворительную оценку на экзамене «1С:Специалист»). Рассмотрим, какими стандартными и эффективными методами можно заменить этот неоптимальный код.
Если вам обязательно нужно выводить в список динамические данные, которые рассчитываются или выбираются из других таблиц, вместо ПриВыводеСтроки используйте обработчик ПриПолученииДанных. Разберем этот механизм подробнее.
В отличие от ПриВыводеСтроки, обработчик ПриПолученииДанных вызывается всего один раз для всей порции строк, которые платформа собирается отобразить на экране (пакетный режим). В этот обработчик передается параметр ОформленияСтрок, содержащий коллекцию оформлений для всех видимых записей.
Посмотрим на пример правильной реализации пакетного получения данных:
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
// Шаг 1. Собираем ссылки на объекты, которые отображаются на экране
МассивСсылок = Новый Массив;
СоответствиеСтрок = Новый Соответствие;
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
// Проверяем, что в строке есть данные
Если ОформлениеСтроки.ДанныеСтроки = Неопределено Тогда
Продолжить;
КонецЕсли;
СсылкаНаДокумент = ОформлениеСтроки.ДанныеСтроки.Ссылка;
МассивСсылок.Добавить(СсылкаНаДокумент);
// Запоминаем связь ссылки и оформления строки для последующего вывода
СоответствиеСтрок.Вставить(СсылкаНаДокумент, ОформлениеСтроки);
КонецЦикла;
Если МассивСсылок.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// Шаг 2. Выполняем ОДИН запрос ко всей порции данных вместо N запросов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВзаиморасчетыОстатки.ДоговорКонтрагента КАК Договор,
| ЕСТЬNULL(ВзаиморасчетыОстатки.СуммаОстаток, 0) КАК ОстатокДолга
|ИЗ
| РегистрНакопления.Взаиморасчеты.Остатки(, ДоговорКонтрагента В (&МассивСсылок)) КАК ВзаиморасчетыОстатки";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Выборка = Запрос.Выполнить().Выбрать();
// Шаг 3. Быстро распределяем полученные данные по оформлению строк из кэша
Пока Выборка.Следующий() Цикл
ОформлениеСтроки = СоответствиеСтрок.Получить(Выборка.Договор);
Если ОформлениеСтроки <> Неопределено Тогда
ОформлениеСтроки.Ячейки.Долг.УстановитьТекст(Выборка.ОстатокДолга);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Результат оптимизации: вместо 20 тяжелых одиночных запросов к базе данных при прокрутке экрана выполняется ровно один легкий запрос по индексу. Нагрузка на сервер СУБД падает в десятки раз, а интерфейс начинает работать плавно и без задержек.
Самым изящным и производительным решением является полное избавление от программного кода заполнения колонок. Все необходимые данные (остатки, реквизиты связанных контрагентов, статусы) можно получить непосредственно в тексте запроса самого динамического списка с помощью конструкции ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN).
В этом случае СУБД сама на уровне индексов выполнит оптимальную сборку данных за один проход, и платформа выдаст на клиентское приложение уже полностью готовый набор строк. Никакого программного кода писать не потребуется вовсе, а нагрузка на систему снизится до минимума.
Если ваша конфигурация переводится на управляемое приложение (платформа 1С 8.3), то в управляемых формах динамические списки работают по совершенно иным, оптимизированным алгоритмам. На управляемых формах событие ПриВыводеСтроки отсутствует как класс.
Для визуального выделения строк (например, окрашивание просроченных документов в красный цвет) используется механизм Условного оформления динамического списка. Условия накладываются декларативно в настройках списка, а вся тяжелая работа по раскраске и оптимизации запросов ложится на технологическую платформу 1С, которая справляется с этим максимально эффективно.
Для более сложных задач в современных версиях платформы (начиная с 8.3.10) у динамических списков появилось событие ПриПолученииДанныхНаСервере. Оно позволяет безопасно и быстро дополнять данные динамического списка сложными серверными алгоритмами без потери отзывчивости клиентского приложения.
Подведем итоги нашего анализа. Свернутая форма списка документов с тяжелыми запросами в событии ПриВыводеСтроки не выполняет эти запросы напрямую в момент сворачивания. Однако она представляет собой «бомбу замедленного действия»:
Решением проблемы является полный отказ от запросов в событии ПриВыводеСтроки в пользу пакетной обработки в ПриПолученииДанных, оптимизации текста запроса динамического списка или перехода на современные механизмы управляемых форм платформы «1С:Предприятие 8.3».