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

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

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

Вариант 1. Классический перебор в обратном цикле

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

Пример кода с обратным перебором:


ВсегоСтрок = ТаблицаЗначений.Количество();
Для Индекс = 1 По ВсегоСтрок Цикл
    ТекущийИндекс = ВсегоСтрок - Индекс;
    СтрокаТЗ = ТаблицаЗначений[ТекущийИндекс];
    Если СтрокаТЗ.Количество = 0 Тогда
        ТаблицаЗначений.Удалить(СтрокаТЗ);
    КонецЕсли;
КонецЦикла;

Этот метод надежен, не требует дополнительной памяти, но на очень больших таблицах он работает медленно, так как каждое удаление заставляет платформу пересчитывать индексы оставшейся коллекции. Выясним причину низкой скорости: чем ближе к началу таблицы находится удаляемая строка, тем больше элементов платформе приходится «сдвигать» в памяти.

Вариант 2. Использование метода НайтиСтроки

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


ПараметрыОтбора = Новый Структура("Количество", 0);
МассивСтрокДляУдаления = ТаблицаЗначений.НайтиСтроки(ПараметрыОтбора);
Для Каждого Стр Из МассивСтрокДляУдаления Цикл
    ТаблицаЗначений.Удалить(Стр);
КонецЦикла;

Посмотрим на результаты тестов: этот метод часто оказывается в 1.5–2 раза быстрее обычного перебора. Почему? Потому что поиск строк реализован на уровне платформенного кода (С++), который работает эффективнее, чем интерпретируемый код 1С. Чтобы еще больше ускорить этот процесс, можно добавить индекс по колонке Количество перед поиском:

ТаблицаЗначений.Индексы.Добавить("Количество");

Однако помните: создание индекса само по себе требует времени, поэтому его стоит использовать только в том случае, если вы выполняете несколько поисков или таблица действительно огромна.

Вариант 3. Использование запроса (Временные таблицы)

Среди разработчиков часто ведется дискуссия: стоит ли передавать таблицу значений в запрос для фильтрации? Разберем ситуацию. Мы можем загрузить ТЗ в менеджер временных таблиц, выбрать данные с условием ГДЕ Количество <> 0 и выгрузить результат обратно в ТЗ.


Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = 
    "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ;
    |ВЫБРАТЬ * ИЗ ВТ_Данные ГДЕ Количество <> 0";
Запрос.УстановитьПараметр("ТЗ", ТаблицаЗначений);
ТаблицаЗначений = Запрос.Выполнить().Выгрузить();

Проанализируем ситуацию: этот метод имеет свои «подводные камни». При передаче ТЗ в запрос происходит сериализация данных и передача их на SQL-сервер (в клиент-серверном варианте). Если в таблице 50 колонок и 100 000 строк, накладные расходы на передачу данных по сети могут превысить выигрыш от скорости работы SQL.

Однако, как показывают замеры, если вам нужно удалить более 50% строк, метод с запросом часто выигрывает у циклов, так как SQL-серверу проще сформировать новую таблицу из нужных строк, чем платформе 1С удалять их по одной из существующей коллекции.

Вариант 4. Метод копирования с отбором

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


// Если нам нужно оставить только те строки, где Количество НЕ равно 0
// Сначала найдем строки, которые мы ХОТИМ ОСТАВИТЬ (нужно заранее знать эти значения)
// Либо воспользуемся НайтиСтроки для получения массива нужных строк
МассивНужныхСтрок = ТаблицаЗначений.НайтиСтроки(Новый Структура("Количество", 10)); 
НоваяТЗ = ТаблицаЗначений.Скопировать(МассивНужныхСтрок);

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

Вариант 5. Особенности работы с табличными частями документов

Если ваша задача — удалить строки из табличной части (ТЧ) документа на форме, правила меняются. Прямое удаление строк из ТЧ в цикле — самая медленная операция из всех возможных, так как при каждом удалении платформа пересчитывает итоги, проверяет условное оформление и вызывает события формы.

Разберем по шагам правильный алгоритм для ТЧ:

  1. Выгружаем табличную часть в объект ТаблицаЗначений через ТЧ.Выгрузить().
  2. Проводим оптимизированное удаление строк в полученной ТЗ (например, через НайтиСтроки или запрос).
  3. Очищаем исходную табличную часть и загружаем в неё результат через ТЧ.Загрузить(ОчищеннаяТЗ).

Этот подход позволяет избежать сотен обновлений интерфейса, заменяя их одним массовым действием.

Сводные рекомендации по выбору метода

На основе проведенного анализа сделаем выводы:

Рассмотрим важный нюанс: при использовании запроса с конструкцией ВЫБРАТЬ *, помните, что это не всегда корректно, если в ТЗ есть колонки с типами, которые нельзя поместить в запрос (например, объекты других коллекций). В таких случаях придется перечислять колонки явно или использовать только программные методы обработки (циклы).

← На главную