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