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

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

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

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

Механика работы индексов в таблице значений

Разберем, как платформа 1С обрабатывает коллекцию Индексы объекта ТаблицаЗначений:

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

Оптимальный порядок построения алгоритма

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

Посмотрим на пример правильной организации кода:


ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Колонка_1", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("Колонка_2", Новый ОписаниеТипов("Строка"));

// Создаем индекс сразу после объявления колонок
ТЗ.Индексы.Добавить("Колонка_1");

// Алгоритм 1: Заполнение с проверкой уникальности
Для Каждого ЭлементДанных Из ИсточникДанных Цикл
    // Поиск выполняется быстро благодаря активному индексу
    НайденнаяСтрока = ТЗ.Найти(ЭлементДанных.Код, "Колонка_1");
    Если НайденнаяСтрока = Неопределено Тогда
        НоваяСтрока = ТЗ.Добавить();
        НоваяСтрока.Колонка_1 = ЭлементДанных.Код;
        НоваяСтрока.Колонка_2 = ЭлементДанных.Наименование;
    КонецЕсли;
КонецЦикла;

// Алгоритм 2: Дозаполнение данных
Для Каждого ДопЭлемент Из ДополнительныйИсточник Цикл
    НайденнаяСтрока = ТЗ.Найти(ДопЭлемент.Код, "Колонка_1");
    Если НайденнаяСтрока <> Неопределено Тогда
        НайденнаяСтрока.Колонка_2 = ДопЭлемент.Наименование;
    КонецЕсли;
КонецЦикла;

Нюансы и ограничения методов поиска по индексу

Обратим внимание на важные технические особенности работы методов поиска в 1С:

  1. Особенность метода Найти(): Индекс используется платформой только в том случае, если поиск выполняется по одной конкретной колонке. Если вторым параметром передать список колонок через запятую (например, "Колонка_1, Колонка_2"), поиск будет выполняться последовательным перебором без использования индексов.
  2. Особенность метода НайтиСтроки(): Данный метод принимает объект Структура. Чтобы поиск задействовал составной индекс (например, "Колонка1, Колонка2"), параметры структуры отбора должны точно соответствовать составу индекса или его левому префиксу.
  3. Сортировка не заменяет индекс: Метод ТЗ.Сортировать(...) выполняет лишь физическую перестановку строк в памяти, но не строит структуру поиска. Вызовы Найти() и НайтиСтроки() на отсортированной, но неиндексированной таблице продолжают работать медленно (полным сканированием).
  4. Селективность данных: Индексирование дает наибольший прирост на колонках с высокой уникальностью значений (ссылки, коды, идентификаторы). Индексировать колонки с низкой селективностью (например, флаги типа Булево) неэффективно.

Альтернативные способы оптимизации

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

  1. Использование объекта Соответствие: Хэш-таблица Соответствие осуществляет поиск по ключу за константное время. Если требуется только проверять уникальность по одному ключу и быстро получать ссылку на строку таблицы, связка ТаблицаЗначений + Соответствие работает еще быстрее:
    
    ТЗ = Новый ТаблицаЗначений;
    ТЗ.Колонки.Добавить("Код");
    ТЗ.Колонки.Добавить("Наименование");
    
    ХэшТаблица = Новый Соответствие;
    
    Для Каждого Элемент Из ИсточникДанных Цикл
        НайденнаяСтрока = ХэшТаблица.Получить(Элемент.Код);
        Если НайденнаяСтрока = Неопределено Тогда
            НоваяСтрока = ТЗ.Добавить();
            НоваяСтрока.Код = Элемент.Код;
            НоваяСтрока.Наименование = Элемент.Наименование;
            
            ХэшТаблица.Вставить(Элемент.Код, НоваяСтрока);
        КонецЕсли;
    КонецЦикла;
    
  2. Пакетное удаление дубликатов методом Свернуть(): Если во время заполнения таблицы нет необходимости сразу обращаться к найденным строкам, наиболее производительно просто заполнить всю таблицу строк без промежуточных проверок, а в конце выполнить метод ТЗ.Свернуть("Колонка_1", ...).
  3. Использование временных таблиц в запросе: При обработке больших массивов (от десятков тысяч строк) часто быстрее передать данные в объект Запрос, выгрузить во временную таблицу с директивой ИНДЕКСИРОВАТЬ ПО и выполнить соединение или группировку средствами СУБД.
← На главную