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