Почему при скролле динамического списка выбирается содержимое всех табличных частей и как это исправить?

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

Рассмотрим ситуацию, с которой часто сталкиваются разработчики при анализе производительности форм в 1С. При просмотре данных в SQL-профайлере обнаруживается, что простое перемещение по строкам динамического списка (например, справочника Номенклатуры) генерирует тяжелые запросы. В частности, из базы выбирается содержимое абсолютно всех табличных частей активного элемента. Проанализируем, почему это происходит и как правильно оптимизировать работу с динамическими списками.

Поведение динамического списка по умолчанию

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

Следовательно, проблема кроется не в самом объекте ДинамическийСписок, а в написанном нами клиентском коде формы, который реагирует на смену активной строки. Обычно это код внутри обработчика события ПриАктивизацииСтроки.

Механизм неявного чтения объекта

Разберем по шагам, что приводит к генерации избыточных SQL-запросов. Главная причина — это неявное чтение объекта целиком. Оно возникает в следующих случаях:

  1. Обращение через точку к реквизитам ссылки. Если в клиентском коде мы пытаемся получить значение через ссылку (например, Элементы.Список.ТекущиеДанные.Ссылка.ВидНоменклатуры), платформа понимает, что нужных данных на клиенте нет. Чтобы их получить, она инициализирует загрузку всего объекта из базы данных в память. Это неизбежно тянет за собой чтение всех его табличных частей (в SQL это таблицы с суффиксом _VT).
  2. Использование контекстных серверных вызовов. Если в событии вызывается процедура с директивой &НаСервере или используется функция РеквизитФормыВЗначение, происходит передача всего контекста формы на сервер и чтение данных объекта.

Решение 1: Расширение запроса динамического списка

Чтобы избежать полного чтения объекта, посмотрим на самое простое архитектурное решение. Любые данные, которые нужны нам для анализа текущей строки или установки отборов, необходимо получать заранее.

Добавим нужные поля (например, реквизиты ссылки) напрямую в текст произвольного запроса динамического списка. В этом случае платформа эффективно выберет данные одним SQL-запросом. Они сразу станут доступны на клиенте в структуре Элементы.Список.ТекущиеДанные, полностью исключая паразитные серверные вызовы и чтение табличных частей.

Решение 2: Оптимизация обработчика "ПриАктивизацииСтроки"

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

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

Проанализируем пример кода:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    Если Элементы.Список.ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Обязательно отменяем предыдущий вызов, если пользователь продолжает скроллить
    ОтключитьОбработчикОжидания("ОбновитьЗависимыеДанные");
    
    // Запускаем вспомогательную процедуру с задержкой 0.3-0.5 секунды
    ПодключитьОбработчикОжидания("ОбновитьЗависимыеДанные", 0.5, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьЗависимыеДанные()
    // Логика выполняется только когда пользователь остановился на конкретной строке
    ТекущаяСтрока = Элементы.Список.ТекущаяСтрока;
    
    // Пример обновления зависимого списка
    ОбщегоНазначенияКлиентСервер.УстановитьПараметрДинамическогоСписка(Аналоги, "Ссылка", ТекущаяСтрока, Истина);
КонецПроцедуры

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

Решение 3: Использование внеконтекстных серверных вызовов

Если для обработки текущей строки нам все же необходимо обратиться к серверу (например, выполнить сложный запрос, который нельзя встроить в динамический список), это нужно делать строго с использованием директивы &НаСервереБезКонтекста.

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

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

← На главную