Что лучше передавать в качестве параметра в запрос 1С: массив или список значений?

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

При разработке в среде «1С:Предприятие» перед программистом регулярно встает задача передачи коллекции значений (например, списка номенклатуры, контрагентов или документов) в параметры запроса для последующей фильтрации с использованием оператора В. На первый взгляд может показаться, что между использованием объекта Массив и объекта СписокЗначений нет принципиальной разницы — запрос успешно отработает в обоих случаях. Однако за этим скрывается целый ряд глубоких архитектурных различий, ограничений платформы, проблем с производительностью и особенностей работы клиент-серверного взаимодействия.

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

1. Внутреннее устройство объектов в памяти (под капотом платформы)

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

Массив — это простейшая, максимально облегченная последовательная коллекция элементов. На уровне платформы «1С:Предприятие» массив представляет собой простой индексированный набор переменных. Каждый элемент массива хранит непосредственно само значение (например, ссылку на элемент справочника СправочникСсылка.Номенклатура, число или строку). У массива нет никаких сопутствующих интерфейсных или служебных свойств. Он идеально оптимизирован для быстрого обхода в цикле и передачи по каналам связи.

Список значений — это сложный, специализированный визуальный (интерфейсный) объект. Он создавался в первую очередь для того, чтобы выводить списки пользователю на форму, организовывать интерактивный выбор элементов, устанавливать пометки и связывать элементы с картинками. Из-за этого каждый элемент списка значений является не просто хранимым значением, а тяжелой системной оберткой типа ЭлементСпискаЗначений. Данный вспомогательный объект принудительно содержит в себе следующие свойства:

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

2. Критическое ограничение динамических списков

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

Если в качестве параметра запроса динамического списка передать объект типа СписокЗначений, то платформа поведет себя следующим образом:

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

3. Передача данных между клиентом и сервером

В управляемом приложении 1С код четко разделен на клиентский и серверный уровни. Передача объектов между ними подчиняется строгим правилам сериализации. Рассмотрим классический пример передачи коллекции с клиента на сервер:


&НаСервере
Процедура ВывестиСписокНаСервере(ПереданнаяКоллекция)
    Для Каждого Элемент Из ПереданнаяКоллекция Цикл
        Сообщить(Элемент.Значение);
    КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьКоманду(Команда)
    Список = Новый СписокЗначений;
    Список.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000001"));
    Список.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000002"));
    ВывестиСписокНаСервере(Список);
КонецПроцедуры

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

Массив же является абсолютно универсальным, немутабельным (с точки зрения неизменности системной структуры) и легковесным контейнером, который гарантированно и без ошибок передается между любыми контекстами выполнения, включая COM-соединения, фоновые задания и веб-сервисы.

4. Влияние на производительность СУБД и оптимизацию запросов

Когда мы передаем массив или список в параметр запроса с условием ГДЕ Ссылка В (&Параметр), платформа транслирует этот запрос на уровень СУБД (MS SQL, PostgreSQL, IBM DB2 или Oracle) в виде конструкции IN (значение1, значение2, ... значениеN).

Здесь вступают в силу ограничения самих систем управления базами данных:

  1. Лимиты по количеству параметров: СУБД имеют жесткие ограничения на число параметров в одном запросе. Например, в Microsoft SQL Server этот лимит составляет 2100 параметров. Если вы попытаетесь передать в условие В (&Параметр) массив, содержащий более 2100 элементов, платформа или СУБД вернут ошибку выполнения.
  2. Деградация планов выполнения: Когда размер списка элементов в условии В превышает 100-200 элементов, оптимизатор СУБД начинает испытывать трудности с построением оптимального плана запроса. Вместо использования эффективного поиска по индексам СУБД может переключиться на полное сканирование таблицы (Index Scan или Table Scan), что приведет к колоссальным задержкам и блокировкам таблиц для других пользователей.

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

Рассмотрим по шагам, как реализовать этот оптимальный механизм:


// Шаг 1. Создаем типизированную Таблицу Значений
ТЗПараметров = Новый ТаблицаЗначений;
ТЗПараметров.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

// Шаг 2. Заполняем таблицу значений данными из исходного массива
Для Каждого СсылкаНоменклатуры Из МассивНоменклатуры Цикл
    НоваяСтрока = ТЗПараметров.Добавить();
    НоваяСтрока.Номенклатура = СсылкаНоменклатуры;
КонецЦикла;

// Шаг 3. Инициализируем Менеджер Временных Таблиц и Запрос
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

// Шаг 4. Помещаем таблицу значений во временную таблицу и индексируем её
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВТ_Данные.Номенклатура КАК Номенклатура
    |ПОМЕСТИТЬ ВТ_Фильтр
    |ИЗ
    |	&ТЗПараметров КАК ВТ_Данные
    |;
    |////////////////////////////////////////////////////////////////////////////////
    |ИНДЕКСИРОВАТЬ ВТ_Фильтр.Номенклатура
    |;";
    
Запрос.УстановитьПараметр("ТЗПараметров", ТЗПараметров);
Запрос.Выполнить();

// Шаг 5. Выполняем основной запрос, соединяясь с временной таблицей
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
    |	ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
    |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Фильтр КАК ВТ_Фильтр
    |		ПО ТоварыНаСкладахОстатки.Номенклатура = ВТ_Фильтр.Номенклатура";

РезультатЗапроса = Запрос.Выполнить().Выгрузить();

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

5. Итоговые правила выбора коллекций (шпаргалка для разработчика)

Чтобы избежать ошибок при проектировании систем и написании программного кода, зафиксируем простые и понятные правила использования коллекций в экосистеме 1С:

  1. Всегда используйте Массив для передачи списочных данных в параметры обычных запросов, если количество элементов заведомо невелико (до 1000 элементов).
  2. Всегда используйте Массив для передачи параметров в запросы Динамических списков. Передача списка значений туда приведет к потере данных (отработает только первый элемент).
  3. Всегда используйте Массив для передачи коллекций простых типов и ссылок с клиента на сервер, в COM-соединения и веб-сервисы.
  4. Используйте Таблицу значений (с помещением во Временную Таблицу), если коллекция элементов для передачи в запрос превышает 1000–2000 элементов.
  5. Используйте Список значений исключительно в интерфейсе. Его прямое назначение — отображение перечней пользователю на управляемых и обычных формах, интерактивный выбор элементов с галочками и иконками.

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

← На главную