В практике программирования на платформе 1С часто возникает задача сопоставления данных из разных источников. Рассмотрим классическую ситуацию: у нас есть табличная часть (ТЧ) документа с колонкой ID и массив, содержащий список нужных нам идентификаторов. Наша цель — эффективно обойти ТЧ и отметить те строки, чьи ID присутствуют в массиве.
Разберем по шагам несколько подходов, от простых до наиболее производительных, и выясним, какой из них лучше использовать в зависимости от объема данных.
Проанализируем работу с объектом Соответствие. Это один из самых быстрых способов поиска в памяти. В 1С Соответствие реализовано как хеш-таблица, что обеспечивает скорость поиска O(1), практически не зависящую от общего количества элементов.
Рассмотрим алгоритм реализации:
Соответствие.ID.
// Подготовим соответствие для быстрого поиска
СлужебноеСоответствие = Новый Соответствие;
Для Каждого ТекID Из МассивИД Цикл
СлужебноеСоответствие.Вставить(ТекID, Истина);
КонецЦикла;
// Обходим ТЧ и проверяем наличие ID
Для Каждого СтрокаТЧ Из Объект.ЗаказВПроизводство Цикл
Если СлужебноеСоответствие[СтрокаТЧ.ID] <> Неопределено Тогда
СтрокаТЧ.Значение = 1;
КонецЕсли;
КонецЦикла;
Если данных очень много (десятки или сотни тысяч строк), эффективнее перенести обработку на сторону SQL-сервера. Выясним причину: база данных использует оптимизированные алгоритмы соединения (например, Hash Join или Merge Join).
Посмотрим на пример кода с использованием временной таблицы:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТаблицаИД.Ссылка КАК ID
|ПОМЕСТИТЬ ВТ_ИскомыеИД
|ИЗ
| &МассивИД КАК ТаблицаИД
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ТЧ.НомерСтроки - 1 КАК Индекс
|ИЗ
| Документ.ЗаказВПроизводство.Товары КАК ТЧ
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ИскомыеИД КАК ВТ
| ПО ТЧ.ID = ВТ.ID
|ГДЕ
| ТЧ.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("МассивИД", МассивИД);
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
Результат = Запрос.Выполнить().Выгрузить();
Для Каждого СтрокаРез Из Результат Цикл
Объект.ЗаказВПроизводство[СтрокаРез.Индекс].Значение = 1;
КонецЦикла;
Если мы работаем не с объектом документа, а с выгруженной таблицей значений, мы можем задействовать метод НайтиСтроки(). Для этого крайне важно предварительно проиндексировать колонку ID.
Рассмотрим, как это ускоряет процесс:
ТаблицаЗначений.ТЗ.Индексы.Добавить("ID").НайтиСтроки().Важно: этот метод эффективен, когда массив идентификаторов значительно меньше, чем количество строк в таблице.
Проанализируем ситуацию, когда идентификаторы являются последовательными целыми числами. В этом случае можно использовать массив 1С как «карту присутствия», где индекс массива соответствует значению ID.
// Создаем массив размером с максимальный ID
МаксИД = 2000000; // Пример
КартаПрисутствия = Новый Массив(МаксИД + 1);
Для Каждого ТекID Из МассивИД Цикл
КартаПрисутствия[ТекID] = Истина;
КонецЦикла;
Для Каждого СтрокаТЧ Из Объект.ЗаказВПроизводство Цикл
// Прямое обращение по индексу - самая быстрая операция
Если КартаПрисутствия[СтрокаТЧ.ID] = Истина Тогда
СтрокаТЧ.Значение = 1;
КонецЕсли;
КонецЦикла;
Этот метод является самым производительным в 1С (быстрее Соответствия), но имеет жесткие ограничения: ID должны быть только положительными целыми числами, а диапазон значений не должен превышать доступную оперативную память.
Подведем итоги нашего исследования:
Массив.Найти() внутри цикла по таблице — это приведет к квадратичной сложности алгоритма O(N*M) и значительным тормозам на больших списках.