Как обойти ограничение в 99 999 строк в документе 1С и разбить загрузку на части?

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

Часто при переносе данных, загрузке остатков из старых конфигураций или внешних баз мы сталкиваемся с задачей загрузки огромного массива информации. Например, при получении данных запросом из регистра накопления товаров может сформироваться выборка размером более 100 000 строк. При попытке загрузить весь этот объем в один документ платформа выдает ошибку, и документ не записывается. Давайте разберем по шагам, почему возникает эта проблема, проанализируем возможные варианты ее решения и рассмотрим примеры кода для корректной обработки данных.

Выясним причину ограничения в 99 999 строк

Исторически в платформе 1С:Предприятие 8 длина системного поля НомерСтроки для табличных частей жестко задана типом Число(5). Именно поэтому максимальное количество строк, которое физически может записаться в базу данных, составляет ровно 99 999. При попытке записать стотысячную строку платформа просто не может присвоить ей следующий порядковый номер из-за ограничения разрядности.

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

Почему не стоит создавать гигантские документы?

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

  1. Скорость проведения и блокировки. Проведение одного документа с 90 тысячами строк может занимать часы. В этот момент создается колоссальная нагрузка на SQL-сервер, а таблицы задействованных регистров полностью блокируются, парализуя работу остальных пользователей.
  2. Трудности поиска ошибок. Если в таком документе возникнет ошибка (например, отрицательный остаток по одной позиции), найти и исправить её будет крайне тяжело.
  3. Оптимальный размер. Рекомендуется разбивать загружаемые данные на порции по 1 000 — 5 000 строк.

Гораздо правильнее делить ввод остатков не просто банальным счетчиком в цикле, а по логическим признакам: например, формировать отдельные документы по каждому складу или по крупным группам номенклатуры (материалы, товары, готовая продукция). Это значительно облегчит последующую сверку остатков.

Программное разбиение выборки на несколько документов

Если мы получаем данные через запрос, самым разумным подходом будет создание новых документов прямо в процессе обхода выборки, так называемыми "порциями". Рассмотрим подробнее, как это реализовать. В данном примере мы установим лимит в 1000 строк на один документ.

Пример реализации алгоритма:


МаксимальноСтрок = 1000;
СчетчикСтрок = 1000; // Инициализируем так, чтобы первый цикл сразу создал новый документ
ОчереднойДокумент = Неопределено;

Пока Выборка.Следующий() Цикл
    
    // Если достигли лимита, записываем текущий документ и создаем новый
    Если СчетчикСтрок >= МаксимальноСтрок Тогда
        Если ОчереднойДокумент <> Неопределено Тогда
            ОчереднойДокумент.Записать(РежимЗаписиДокумента.Проведение);
        КонецЕсли;
        
        СчетчикСтрок = 0;
        ОчереднойДокумент = Документы.ВводНачальныхОстатков.СоздатьДокумент();
        ОчереднойДокумент.Дата = ТекущаяДата();
        ОчереднойДокумент.Склад = Выборка.Склад;
        // Здесь заполняем другие реквизиты шапки документа
    КонецЕсли;
    
    СчетчикСтрок = СчетчикСтрок + 1;
    НоваяСтрока = ОчереднойДокумент.Товары.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка); // Переносим значения из выборки в ТЧ
    
КонецЦикла;

// Не забываем записать и провести последний созданный документ
Если ОчереднойДокумент <> Неопределено Тогда
    ОчереднойДокумент.Записать(РежимЗаписиДокумента.Проведение);
КонецЕсли;

Этот код позволяет равномерно распределить весь объем данных по нескольким документам, избегая превышения лимитов и снижая пиковую нагрузку на сервер БД.

Как заполнить несколько табличных частей одновременно?

Часто возникает ситуация, когда в один документ нужно загрузить данные в несколько табличных частей (например, «Товары» и «Цены номенклатуры»). Разберем по шагам, как действовать в такой ситуации:

  1. Данные из одного запроса: Если данные для обеих ТЧ получаются в рамках одной выборки, вы просто добавляете строки в обе таблицы внутри одного прохода цикла, увеличивая общий счетчик строк.
  2. Данные из разных запросов: Если выборки разные, алгоритм усложняется. Во время прохода первой выборки созданные объекты документов (ДокументОбъект) не записываются сразу, а помещаются в массив или таблицу значений (в кэш). Затем вы обходите вторую выборку, находите в кэше нужный документ по ключу (например, по складу) и дозаполняете вторую табличную часть. Только после завершения формирования обеих ТЧ документы записываются.

Обновление платформы: снятие ограничений с версии 8.3.27

Посмотрим на актуальные изменения платформы. Поскольку 1С всё чаще внедряется в крупном энтерпрайз-сегменте, разработчики платформы сняли жесткое ограничение на 100 тысяч строк. Начиная с версии 1С:Предприятие 8.3.27, в свойствах объекта метаданных ТабличнаяЧасть появилось свойство ДлинаНомераСтроки (в англоязычном синтаксисе LineNumberLength).

Теперь разработчик может прямо в конфигураторе увеличить это значение со стандартных 5 до 9. Это позволит хранить в одной табличной части вплоть до 999 999 999 строк. Однако, применять эту настройку стоит с большой осторожностью из-за причин падения производительности, описанных нами выше.

Нестандартные способы обхода (если разбивать категорически нельзя)

Иногда заказчики ставят жесткое условие: загрузить внешний файл строго в один документ (например, для удобства визуального контроля "один к одному"). Если платформа ниже версии 8.3.27, проанализируем обходные маневры:

  1. Использование хранилища значений: В документ добавляется реквизит с типом ХранилищеЗначения. В процедуре ПередЗаписью вы выгружаете табличную часть в объект ТаблицаЗначений, помещаете её в хранилище, а саму табличную часть документа очищаете. При открытии формы в процедуре ПриЧтенииНаСервере данные достаются из хранилища и загружаются в форму. Алгоритм проведения переписывается так, чтобы он брал данные не из физической ТЧ, а распаковывал из хранилища.
  2. Использование регистра сведений: Вместо табличной части документа создается подчиненный регистр сведений. Данные пишутся напрямую в регистр (где нет лимита строк). А на форме документа размещается ДинамическийСписок, который показывает записи этого регистра с отбором по ссылке на текущий документ. Этот способ гораздо более стабилен и предпочтителен при огромных объемах данных.

Используйте приведенные примеры и подходы, чтобы грамотно оптимизировать алгоритмы начального ввода данных и обеспечивать стабильную работу баз 1С.

← На главную