В практике администрирования и разработки на платформе 1С:Предприятие нередко возникают ситуации, когда система начинает вести себя нестабильно: возникают «фризы», кратковременные зависания интерфейса, при которых программа не откликается на действия пользователя в течение нескольких секунд. Особенно коварны случаи, когда эти тормоза носят периодический характер и проявляются только у определенных сотрудников, независимо от мощности их рабочих станций. В этой статье мы подробно разберем одну из таких неочевидных причин, связанных с работой динамических списков в обычных формах, проанализируем, почему стандартные инструменты диагностики могут подвести, и найдем оптимальные пути решения.
Рассмотрим типичную ситуацию: пользователь жалуется на то, что 1С «замирает» каждые 10–15 секунд на интервал от 5 до 7 секунд. При этом работа в других приложениях на компьютере продолжается в штатном режиме. Первым делом мы, как квалифицированные специалисты, обращаемся к стандартным методам диагностики. Давайте разберем по шагам, что обычно проверяется в таких случаях:
Разберем, почему так происходит. Ситуация осложняется тем, что проблема скрыта внутри механизмов самой платформы, которые не всегда прозрачны для встроенного отладчика.
Проанализируем поведение системы более детально. Если замер производительности не показывает аномалий в коде, значит, задержка происходит либо на уровне взаимодействия платформы с СУБД, либо на этапе отрисовки графического интерфейса. В рассматриваемом случае в журнале реализации (или любом другом крупном списке документов) было обнаружено около 500 000 записей.
Причина оказалась до боли простой, но скрытой в глубоких настройках списка: установленный флаг «Обновлять автоматически каждые 10 секунд». Выясним, почему этот стандартный функционал вызывает такие катастрофические последствия.
В обычных формах (которые используются, например, в 1С:Предприятие 8.3.9.2033 или старых редакциях УПП и КА) механизм обновления динамических списков работает не так изящно, как в современных управляемых формах. Когда срабатывает таймер автообновления, платформа инициирует процесс актуализации данных. Если журнал содержит сотни тысяч документов, а пользователь настроил сложные отборы или сортировки, система вынуждена выполнять ресурсоемкие операции по пересчету позиций курсора и обновлению видимых строк.
Это ключевой вопрос, который часто ставит в тупик разработчиков. Разберем физику процесса:
Стандартный Замер производительности фиксирует время выполнения кода, написанного программистом (процедуры, функции). Однако при автоматическом обновлении списка основная нагрузка ложится на служебные вызовы платформы. Платформа выполняет неявные запросы к СУБД для получения порции данных. Эти запросы выполняются «внутри» объекта списка и не отображаются как исполнение строк кода на встроенном языке. Кроме того, значительная часть времени тратится на отрисовку графического интерфейса (GUI). Перестроение визуального дерева элементов в обычных формах при обновлении огромного списка потребляет ресурсы видеоподсистемы и процессора клиентской машины, что абсолютно не фиксируется серверными замерами.
Рассмотрим несколько вариантов решения этой проблемы, начиная от самых простых и заканчивая архитектурными изменениями.
Самое быстрое и очевидное решение — снять тот самый злополучный флажок в настройках списка. Посмотрим, как это сделать программно для всех пользователей, чтобы предотвратить повторение ситуации:
// Пример отключения автообновления для формы списка
Процедура ПриОткрытии()
// Если это список с огромным количеством данных
ЭлементыФормы.СправочникСписок.АвтоОбновление = Ложь;
// Или для журналов документов
ЭлементыФормы.ДокументСписок.АвтоОбновление = Ложь;
КонецПроцедуры
Это мгновенно снимет нагрузку с клиентского компьютера и устранит периодические «замирания».
Если пользователю критически важно видеть актуальные документы, проанализируем возможность ограничения выборки. Журнал из 500 000 документов — это, как правило, данные за несколько лет. Пользователю для оперативной работы редко нужны данные старше месяца. Настройка автоматического отбора по периоду значительно снизит нагрузку при обновлении, так как сократит выборку с сотен тысяч до нескольких тысяч записей.
Выясним, по каким полям пользователь чаще всего строит отборы. Если в журнале включен отбор по полю Контрагент или Склад, и по этим полям в СУБД не построены индексы, то каждое автообновление будет заставлять SQL-сервер выполнять полное сканирование таблицы (Full Table Scan). Убедитесь, что для всех полей, участвующих в поиске и сортировке, установлены соответствующие свойства в метаданных («Индексировать»).
Вместо стандартной галки, которая жестко обновляет весь список, мы можем реализовать более интеллектуальный механизм. Рассмотрим пример использования обработчика ожидания, который будет обновлять список реже или при определенных условиях:
// В модуле формы
Процедура ПриОткрытии()
ПодключитьОбработчикОжидания("ОбновитьСписокДокументов", 60); // Обновляем раз в минуту
КонецПроцедуры
Процедура ОбновитьСписокДокументов()
// Обновляем только если форма активна
Если ЭтаФорма.Активная Тогда
ЭлементыФормы.ДокументСписок.Обновить();
КонецЕсли;
КонецПроцедуры
Важно отметить, что версия платформы 8.3.9.2033 имела ряд известных проблем с управлением памятью в процессе 1cv8.exe при длительной работе с динамическими списками в режиме обычных форм. Проблема «нарастала» со временем: чем дольше у пользователя была открыта форма журнала с включенным автообновлением, тем тяжелее становились тормоза. Это объясняет, почему очистка кэша не помогала — настройки автообновления и состав колонок хранятся в базе данных (в системном хранилище настроек), и «переезжают» за пользователем на любой компьютер.
Подведем итоги нашего исследования. Если вы столкнулись с необъяснимыми тормозами 1С, которые не видны в замере производительности:
Своевременная диагностика таких «мелочей», как лишняя галочка в настройках интерфейса, способна сэкономить десятки часов рабочего времени программистов и нервы пользователей.