Как быстро создать нужное количество строк в таблице значений в 1С?

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

Приветствуем, коллеги! В процессе разработки на платформе 1С:Предприятие часто возникает задача заполнения таблицы значений (ТЗ) данными из массивов. Типичный сценарий: у нас есть массив значений и пустая таблица значений с одной или несколькими колонками. Мы хотим воспользоваться удобным системным методом ЗагрузитьКолонку(), однако сталкиваемся с технической особенностью платформы, которая требует предварительной подготовки структуры данных. В этой статье мы подробно разберем, как решить эту задачу максимально быстро и эффективно.

Почему метод ЗагрузитьКолонку() требует предварительного создания строк?

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

Если ваша исходная таблица значений пуста, метод выполнится абсолютно корректно и без ошибок, но на выходе вы получите всё ту же пустую таблицу. Именно поэтому перед вызовом этого метода разработчику необходимо предварительно наполнить таблицу значений пустыми строками, количество которых строго совпадает с количеством элементов в исходном массиве. Ниже мы детально рассмотрим несколько способов реализации этой задачи.

Способ 1. Простой обход в цикле (классический метод)

Самый очевидный и простой вариант — написать классический цикл добавления строк. Давайте посмотрим на пример реализации такого кода:


// Предположим, у нас есть массив "МассивДанных" и пустая таблица значений "ТЗДанные"
КоличествоЭлементов = МассивДанных.Количество();

Для Счетчик = 1 По КоличествоЭлементов Цикл
    ТЗДанные.Добавить();
КонецЦикла;

// Теперь мы можем безопасно загрузить данные
ТЗДанные.ЗагрузитьКолонку(МассивДанных, "ИмяКолонки");

Оценка производительности: Многие разработчики интуитивно пытаются избегать циклов, опасаясь снижения скорости работы системы. Однако, как показывает практика и реальные замеры производительности на платформе 1С v8.3, простой перебор в цикле и добавление пустых строк выполняются чрезвычайно быстро. Например, создание 120 000 строк в цикле на стороне сервера занимает меньше одной секунды. Для большинства повседневных задач автоматизации этого метода более чем достаточно.

Способ 2. Оптимизированный генератор строк через запрос (без громоздких UNION ALL)

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

Рассмотрим, как можно сгенерировать таблицу с нужным количеством строк без обращения к реальным таблицам базы данных и без ручного написания огромного количества объединений ОБЪЕДИНИТЬ ВСЕ (или UNION ALL).

Мы можем программно сформировать небольшую вспомогательную таблицу из 10 строк, передать её в запрос в качестве параметра, а затем размножить строки с помощью перекрестного соединения (декартова произведения) этой таблицы самой с собой. Посмотрим на этот алгоритм по шагам:

  1. Создаем временную таблицу из 10 строк (числа от 0 до 9) — это происходит мгновенно.
  2. Передаем её в запрос как параметр.
  3. В запросе соединяем таблицу саму с собой нужное количество раз (для получения 10 000 строк достаточно 4 соединений, для 100 000 — 5 соединений).
  4. Ограничиваем итоговый выбор конструкцией ВЫБРАТЬ ПЕРВЫЕ &Количество, передавая туда размер нашего массива.

Давайте проанализируем пример кода, реализующий этот подход:


// 1. Создаем мини-ТЗ с цифрами для разрядов
ТЗЦифры = Новый ТаблицаЗначений;
ТЗЦифры.Колонки.Добавить("Цифра", Новый ОписаниеТипов("Число"));
Для Индекс = 0 По 9 Цикл
    НоваяСтрока = ТЗЦифры.Добавить();
    НоваяСтрока.Цифра = Индекс;
КонецЦикла;

// 2. Инициализируем запрос
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТаблицаЦифр", ТЗЦифры);
Запрос.УстановитьПараметр("НужноеКоличество", МассивДанных.Количество());

// 3. Текст запроса с декартовым произведением
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТаблицаЦифр.Цифра КАК Цифра
    |ПОМЕСТИТЬ ВТ_Цифры
    |ИЗ
    |	&ТаблицаЦифр КАК ТаблицаЦифр
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ ПЕРВЫЕ &НужноеКоличество
    |	(Разряд1.Цифра + Разряд2.Цифра * 10 + Разряд3.Цифра * 100 + Разряд4.Цифра * 1000 + Разряд5.Цифра * 10000) КАК Число
    |ИЗ
    |	ВТ_Цифры КАК Разряд1
    |		CROSS СОЕДИНЕНИЕ ВТ_Цифры КАК Разряд2
    |		CROSS СОЕДИНЕНИЕ ВТ_Цифры КАК Разряд3
    |		CROSS СОЕДИНЕНИЕ ВТ_Цифры КАК Разряд4
    |		CROSS СОЕДИНЕНИЕ ВТ_Цифры КАК Разряд5
    |УПОРЯДОЧИТЬ ПО
    |	Число";

// 4. Выгружаем результат напрямую в ТЗ
ТЗДанные = Запрос.Выполнить().Выгрузить();

// 5. Теперь у нас есть ТЗ нужной длины, можем загрузить колонку
ТЗДанные.Колонки.Добавить("ИмяКолонки"); // Обязательно добавляем целевую колонку, если выгрузили только "Число"
ТЗДанные.ЗагрузитьКолонку(МассивДанных, "ИмяКолонки");

Преимущества метода: Сборка таблицы значений на стороне СУБД или во временных таблицах платформы с последующей выгрузкой через Выгрузить() работает на уровне скомпилированного C++ кода платформы. Память под результирующую таблицу выделяется сразу всем единым блоком, что минимизирует фрагментацию памяти и нагрузку на процессор по сравнению с построчным добавлением в цикле.

Способ 3. Использование готовых механизмов БСП (Библиотеки Стандартных Подсистем)

Если вы ведете разработку в современной конфигурации, где внедрена БСП (например, 1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей или 1С:Бухгалтерия), вам не обязательно писать велосипеды и самостоятельно изобретать алгоритмы заполнения. В составе БСП есть отличные оптимизированные программные интерфейсы для работы с коллекциями.

Обратите внимание на процедуру ДополнитьТаблицуИзМассива() из общего модуля ОбщегоНазначенияКлиентСервер. Она выполняет именно ту задачу, которая нам нужна.

Рассмотрим пример использования этой системной функции:


// Инициализируем пустую ТЗ с нужной нам колонкой
ТЗДанные = Новый ТаблицаЗначений;
ТЗДанные.Колонки.Добавить("ИмяКолонки");

// Вызываем готовую функцию БСП
ОбщегоНазначенияКлиентСервер.ДополнитьТаблицуИзМассива(ТЗДанные, МассивДанных, "ИмяКолонки");

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

Подведем итоги: какой способ выбрать?

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

  1. Если объем вашего массива небольшой (до 50 000 – 100 000 строк), смело используйте стандартный обход в цикле с методом Добавить(). Этот код пишется за пару секунд, работает стабильно и не нагружает базу данных лишними запросами.
  2. Если в вашей конфигурации присутствует БСП, всегда отдавайте предпочтение вызову встроенного метода ОбщегоНазначенияКлиентСервер.ДополнитьТаблицуИзМассива(). Это повышает культуру кода и упрощает его дальнейший аудит.
  3. Для экстремальных нагрузок, сложных фоновых заданий или систем интеграции с объемами данных в сотни тысяч и миллионы строк, используйте метод генерации строк через перекрестное соединение в запросе. Это позволит снизить нагрузку на интерпретатор 1С и оптимально использовать оперативную память сервера приложений.
← На главную