Как эффективно отображать большие списки данных с программным отбором в обычных формах 1С 8.2?

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

При работе с устаревшими, но все еще актуальными конфигурациями на обычных формах (платформа 8.2 или 8.3 в режиме совместимости), программисты часто сталкиваются с проблемой производительности интерфейса. Типичная ситуация: необходимо показать пользователю список из 200 000 позиций номенклатуры, но при этом наложить сложный программный отбор, который отсекает лишь малую часть записей. Использование стандартной ТаблицыЗначений в таких случаях приводит к колоссальному потреблению оперативной памяти и «зависанию» клиента, а привычный по управляемым формам объект ДинамическийСписок с произвольным запросом в классических обычных формах отсутствует в явном виде.

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

Метод 1. Использование стандартного отбора в формах списков

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

Рассмотрим пример программной установки отбора в форме списка, когда нам нужно отфильтровать данные по конкретным критериям перед открытием:


// Пример установки отбора при открытии формы списка
ФормаСписка = Справочники.Номенклатура.ПолучитьФормуСписка(, ЭтаФорма);

// Устанавливаем вид сравнения и значение
ФормаСписка.Отбор.Ссылка.ВидСравнения  = ВидСравнения.ВСписке;
ФормаСписка.Отбор.Ссылка.Значение      = МассивНужныхСсылок; // Осторожно при больших объемах!
ФормаСписка.Отбор.Ссылка.Использование = Истина;

ФормаСписка.Открыть();

Важный нюанс: как было отмечено в обсуждении, если МассивНужныхСсылок содержит десятки тысяч элементов, этот метод станет «узким местом». Платформа будет генерировать SQL-запрос с огромным количеством параметров в условии WHERE IN (...), что может привести к деградации производительности всей СУБД.

Метод 2. Построитель отчета как источник данных для табличного поля

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

Разберем по шагам, как связать запрос с интерфейсом:

  1. Разместим на форме ТабличноеПоле.
  2. В качестве источника данных укажем результат работы построителя.

Рассмотрим пример кода для инициализации такого списка:


Построитель = Новый ПостроительОтчета;
Построитель.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка,
    |   Номенклатура.Код,
    |   Номенклатура.Наименование
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Ссылка В (&МассивФильтра)";

Построитель.Параметры.Вставить("МассивФильтра", СписокСсылок);
Построитель.Выполнить();

// Привязываем результат к табличному полю
ЭлементыФормы.ТабличноеПолеСписок.Значение = Построитель.Результат.Выгрузить();
ЭлементыФормы.ТабличноеПолеСписок.СоздатьКолонки();

Однако, чтобы не грузить все 180 000 строк в память (что и требовалось автору вопроса), мы можем использовать ПостроительЗапроса и выводить данные порционно или использовать виртуализацию.

Метод 3. Вспомогательный регистр сведений («Буфер отборов»)

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

Алгоритм действий следующий:

  1. Создаем индексированный регистр сведений СоставСписковПользователей с измерениями Пользователь (тип Ссылка) и Объект (тип Ссылка на Номенклатуру).
  2. Перед открытием формы программно (запросом) заполняем этот регистр нужными ссылками для текущего пользователя.
  3. В форме списка устанавливаем отбор по этому регистру через соединение или условие В (ВЫБРАТЬ Объект ИЗ РегистрСведений.СоставСписковПользователей ГДЕ Пользователь = &ТекущийПользователь).

Этот метод позволяет платформе работать максимально быстро, так как SQL-сервер использует оптимальный план запроса на основе индексов таблиц БД, а не перебирает гигантский текстовый список параметров.

Метод 4. Виртуализация через событие «ПриВыводеСтроки»

Выясним, как минимизировать потребление памяти, если нам всё же приходится использовать ТаблицуЗначений. Основная проблема — хранение всех данных (строк, чисел, дат) для каждой из 180 000 записей. Мы можем хранить в ТаблицеЗначений только ключевое поле (например, Ссылка).

Рассмотрим реализацию подгрузки данных «на лету»:


Процедура ТабличноеПолеПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    // ДанныеСтроки содержат только Ссылку
    ТекСсылка = ДанныеСтроки.Ссылка;
    
    // Подтягиваем только нужные данные для отображения конкретной строки
    // В реальной задаче лучше использовать кэширование или запрос к выборке
    ОформлениеСтроки.Ячейки.Наименование.УстановитьТекст(ТекСсылка.Наименование);
    ОформлениеСтроки.Ячейки.Артикул.УстановитьТекст(ТекСсылка.Артикул);
КонецПроцедуры

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

Метод 5. Использование Управляемых форм в обычном приложении

Как справедливо заметили участники обсуждения, в платформе 8.2 и выше существует возможность использовать управляемые формы даже в конфигурациях, работающих в обычном режиме. Это позволяет задействовать полноценный объект ДинамическийСписок с его мощным механизмом ПроизвольныйЗапрос.

Чтобы реализовать этот подход, выполним следующие шаги:

  1. В свойствах конфигурации убедимся, что включен флаг «Использовать управляемые формы в обычном приложении».
  2. Создадим новую управляемую форму для справочника.
  3. Добавим на неё реквизит с типом ДинамическийСписок.
  4. В настройках списка пропишем запрос, включающий необходимые условия и соединения с табличными частями.

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

Итоги

Разберем, какой метод выбрать в зависимости от условий:

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

← На главную