Рассмотрим ситуацию, с которой часто сталкиваются разработчики при анализе производительности форм в 1С. При просмотре данных в SQL-профайлере обнаруживается, что простое перемещение по строкам динамического списка (например, справочника Номенклатуры) генерирует тяжелые запросы. В частности, из базы выбирается содержимое абсолютно всех табличных частей активного элемента. Проанализируем, почему это происходит и как правильно оптимизировать работу с динамическими списками.
Для начала выясним причину на базовом уровне. Если мы создадим пустую конфигурацию с одним справочником, добавим в него несколько табличных частей и выведем динамический список на форму, трассировка покажет отсутствие запросов к табличным частям при скролле. Поведение платформы по умолчанию абсолютно корректно.
Следовательно, проблема кроется не в самом объекте ДинамическийСписок, а в написанном нами клиентском коде формы, который реагирует на смену активной строки. Обычно это код внутри обработчика события ПриАктивизацииСтроки.
Разберем по шагам, что приводит к генерации избыточных SQL-запросов. Главная причина — это неявное чтение объекта целиком. Оно возникает в следующих случаях:
Элементы.Список.ТекущиеДанные.Ссылка.ВидНоменклатуры), платформа понимает, что нужных данных на клиенте нет. Чтобы их получить, она инициализирует загрузку всего объекта из базы данных в память. Это неизбежно тянет за собой чтение всех его табличных частей (в SQL это таблицы с суффиксом _VT).&НаСервере или используется функция РеквизитФормыВЗначение, происходит передача всего контекста формы на сервер и чтение данных объекта.Чтобы избежать полного чтения объекта, посмотрим на самое простое архитектурное решение. Любые данные, которые нужны нам для анализа текущей строки или установки отборов, необходимо получать заранее.
Добавим нужные поля (например, реквизиты ссылки) напрямую в текст произвольного запроса динамического списка. В этом случае платформа эффективно выберет данные одним SQL-запросом. Они сразу станут доступны на клиенте в структуре Элементы.Список.ТекущиеДанные, полностью исключая паразитные серверные вызовы и чтение табличных частей.
Событие ПриАктивизацииСтроки срабатывает непрерывно при каждом смещении фокуса (например, когда пользователь зажал стрелку вниз на клавиатуре). Выполнение тяжелой логики или обновление других списков в этом обработчике гарантированно приведет к "фризам" интерфейса.
Рассмотрим стандарты оптимизации 1С для таких случаев. Вместо прямого выполнения логики применяется отложенный вызов через метод ПодключитьОбработчикОжидания.
Проанализируем пример кода:
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
Если Элементы.Список.ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Обязательно отменяем предыдущий вызов, если пользователь продолжает скроллить
ОтключитьОбработчикОжидания("ОбновитьЗависимыеДанные");
// Запускаем вспомогательную процедуру с задержкой 0.3-0.5 секунды
ПодключитьОбработчикОжидания("ОбновитьЗависимыеДанные", 0.5, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьЗависимыеДанные()
// Логика выполняется только когда пользователь остановился на конкретной строке
ТекущаяСтрока = Элементы.Список.ТекущаяСтрока;
// Пример обновления зависимого списка
ОбщегоНазначенияКлиентСервер.УстановитьПараметрДинамическогоСписка(Аналоги, "Ссылка", ТекущаяСтрока, Истина);
КонецПроцедуры
Такой подход отсеивает все промежуточные строки при быстром пролистывании. Реальное обращение к данным произойдет только после того, как скролл остановится.
Если для обработки текущей строки нам все же необходимо обратиться к серверу (например, выполнить сложный запрос, который нельзя встроить в динамический список), это нужно делать строго с использованием директивы &НаСервереБезКонтекста.
Контекстный вызов при скроллинге списка приводит к тому, что платформа каждый раз сериализует и перегоняет между клиентом и сервером весь контекст формы. Во внеконтекстную функцию достаточно передать нужную ссылку параметром, что радикально снизит нагрузку на сервер и сеть.
Резюмируем: чтобы табличные части не читались при скролле, вынесите необходимые реквизиты в запрос динамического списка, избавьтесь от обращений к ссылке "через точку" на клиенте и оберните обновление зависимых данных в однократный обработчик ожидания.