При проектировании систем в 1С разработчики нередко сталкиваются с необходимостью загрузки и обработки массивов данных объемом в сотни тысяч строк (чеки, биллинг, детальные выгрузки из внешних систем). Стандартная табличная часть документа исторически имеет жесткое платформенное ограничение на 99 999 строк, связанное с фиксированной длиной служебного поля НомерСтроки (LineNo). Попытки обойти это ограничение «в лоб» часто приводят к падению производительности и ошибкам переполнения памяти.
Разберем, почему стандартные подходы не работают с большими массивами, и рассмотрим проверенные архитектурные паттерны для работы со сверхбольшими объемами данных.
Частая идея начинающих разработчиков — создать реквизит формы с типом ТаблицаЗначений и загружать данные в него, считывая или записывая их в регистр сведений. Проанализируем, к чему это приводит на практике:
ЗначениеВДанныеФормы и ДанныеФормыВЗначение вызывает колоссальный трафик и зависание интерфейса.Memory Allocation Error и аварийное завершение сеанса.Рассмотрим правильную реализацию хранения строк вне табличной части. Данные строк сохраняются в регистр сведений, а на форму документа помещается ДинамическийСписок.
При реализации этого подхода важно учитывать следующие правила:
ДокументОснование) с типом ссылки на наш документ. Устанавливаем свойство Ведущее — это обеспечит автоматический контроль ссылочной целостности и удаление записей при удалении документа.ОсновнаяТаблица (наш регистр сведений). Не используем произвольные запросы с соединениями к неиндексированным таблицам. Это позволяет платформе выполнять быструю серверную пагинацию (порционную выборку данных по мере прокрутки списка пользователем).Разберем подход, при котором большой массив разбивается на атомарные простые документы без табличных частей. Вся пачка связывается общим документом-пакетом или реквизитом шапки.
Если строки документа нужны только для разовой загрузки и последующего формирования движений, а интерактивное редактирование каждой строки не требуется, оптимально использовать потоковое хранение:
ХранилищеЗначения в виде сжатого файла, JSON или бинарного потока.ЧтениеJSON или ЧтениеXML) без загрузки всего массива в оперативную память.Посмотрим на пример порционной записи наборов движений при потоковой обработке:
// Порционная запись движений для предотвращения переполнения памяти
Набор = РегистрыНакопления.Продажи.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Ссылка);
Счетчик = 0;
Для Каждого СтрокаДанных Из ПотокДанных Цикл
Движение = Набор.Добавить();
ЗаполнитьЗначенияСвойств(Движение, СтрокаДанных);
Счетчик = Счетчик + 1;
Если Счетчик % 5000 = 0 Тогда
// Записываем порцию и очищаем набор
Набор.Записать(Ложь);
Набор.Очистить();
КонецЕсли;
КонецЦикла;
Если Набор.Количество() > 0 Тогда
Набор.Записать(Ложь);
КонецЕсли;
При работе с документами экстремального объема обязательно учитываем сопутствующие настройки платформы: