При разработке в среде 1С:Предприятие 8.3 на управляемых формах начинающие (и даже опытные) разработчики часто сталкиваются с вопросами производительности табличных частей (ТЧ). Существует множество мифов о жестких лимитах на количество строк: кто-то говорит о 99 999 строках, кто-то — о 10 000 строках, доступных на клиенте. В этой статье мы подробно разберем, как на самом деле платформа работает с данными таблиц, какие ограничения являются реальными, а какие — вымышленными, и как правильно писать код для обработки больших массивов данных.
Давайте сразу внесем ясность: в платформе 1С 8.x не существует жесткого программного ограничения в 10 000 или 99 999 строк для работы на клиенте. Технически вам доступны все строки, которые загружены в объект ДанныеФормыКоллекция (это тип, который представляет табличную часть на стороне формы).
Рассмотрим, откуда берутся эти цифры и что ограничивает нас на самом деле:
Проанализируем ситуацию, когда пользователь открывает документ с очень большой табличной частью. Почему интерфейс не «зависает» намертво, если строк действительно много? Здесь вступает в дело механизм подкачки данных порциями.
Для отображения данных в таблице на форме платформа запрашивает у сервера не все строки сразу, а только те, которые видны на экране, плюс небольшой запас (обычно это порции по 20–45 строк). Это позволяет пользователю мгновенно увидеть начало списка. Однако важно понимать: если вы начнете перебирать строки табличной части в цикле в коде на клиенте, платформа будет вынуждена подкачивать остальные строки с сервера, что может вызвать микро-задержки.
Выясним причину, по которой работа с большими ТЧ на клиенте считается плохой практикой. Основная проблема — не в количестве строк как таковом, а в процессе сериализации при контекстных серверных вызовах.
Когда вы вызываете процедуру с директивой &НаСервере из модуля формы, происходит следующее:
Если в вашей таблице 10 000 строк, то даже при выполнении простейшей команды «Проверить заполнение» система будет гонять через сеть мегабайты данных. Именно поэтому на клиенте всё кажется медленным.
Рассмотрим пример кода, предложенный в обсуждении, и разберем его ошибки:
&НаКлиенте
Процедура ЗаполнитьПоНакладной(Команда)
Объект.Товары.Очистить();
// ДанныеЗаполнения — это ссылка на другой документ
ДанныеЗаполнения = Объект.ПриходнаяНакладная;
Для каждого СтрокаТЧ из ДанныеЗаполнения.Товары Цикл
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрокаТЧ.Товар;
НоваяСтрока.Цена = СтрокаТЧ.Цена;
КонецЦикла;
Сообщить("Товары загружены!");
КонецПроцедуры
Почему этот код будет работать плохо?
Во-первых, обращение к ДанныеЗаполнения.Товары на клиенте (где ДанныеЗаполнения — это ссылка) недопустимо или крайне неэффективно. Ссылка не содержит внутри себя данных табличной части. При попытке прочитать Товары через точку от ссылки, платформа выполнит неявный (скрытый) серверный вызов, чтобы получить эти данные. Делать это в цикле — верный способ заставить программу «задуматься» надолго.
Во-вторых, модификация коллекции Объект.Товары на клиенте в большом цикле заставляет интерфейс постоянно пересчитывать итоги и обновлять элементы управления, что также замедляет процесс.
Разберем, как переписать этот алгоритм правильно. Мы должны минимизировать передачу данных и выполнять тяжелые операции там, где данные находятся физически — на сервере.
Рекомендуемый подход:
&НаСервере для заполнения.Посмотрим на оптимизированный пример:
&НаСервере
Процедура ЗаполнитьПоНакладнойНаСервере()
// Мы работаем на сервере, здесь обращение к Ссылке эффективно
СсылкаИсточник = Объект.ПриходнаяНакладная;
Если СсылкаИсточник.Пустая() Тогда
Возврат;
КонецЕсли;
// Очищаем текущую ТЧ
Объект.Товары.Очистить();
// Загружаем данные. Лучше всего использовать Запрос,
// но для учебных целей покажем заполнение из объекта источника
ДокОбъектИсточник = СсылкаИсточник.ПолучитьОбъект();
Для каждого СтрокаИсточника Из ДокОбъектИсточник.Товары Цикл
НоваяСтрока = Объект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточника);
// Если имена колонок отличаются, заполняем вручную
НоваяСтрока.Номенклатура = СтрокаИсточника.Товар;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ЗаполнитьПоНакладной(Команда)
ЗаполнитьПоНакладнойНаСервере();
Сообщить("Товары загружены оперативно на сервере!");
КонецПроцедуры
Если табличная часть документа содержит тысячи строк, даже обычный вызов &НаСервере будет медленным из-за передачи всего Объекта. В таких случаях проанализируем ситуацию: нужно ли нам передавать на сервер все данные формы?
Если нам нужно только заполнить таблицу на основе ссылки, лучше использовать &НаСервереБезКонтекста. В этом случае на сервер передается только Ссылка, а обратно возвращается только массив или таблица значений с нужными строками. Это максимально быстрый способ взаимодействия.
В работе с табличными частями в 1С:Предприятие 8.3 следует придерживаться следующих правил:
ЗаполнитьЗначенияСвойств работает быстрее, чем ручное присваивание каждого реквизита в строке.Таким образом, ограничение в 10 000 строк — это скорее психологическая и архитектурная отметка, после которой разработчик обязан задуматься об оптимизации и переносе логики в правильные программные контексты.