Что быстрее для поиска данных: Соответствие или индексированная ТаблицаЗначений?

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

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

Алгоритмическая сложность: хеш-таблица против дерева поиска

Для понимания разницы в скорости сопоставим теоретическую сложность (Big O) основных операций поиска по ключу:

  1. Объект Соответствие: Внутренне устроен на базе хеш-таблицы. Для извлечения значения по ключу платформа вычисляет хеш переданного объекта и обращается напрямую к соответствующей корзине (bucket). В среднем временная сложность поиска составляет O(1) — операция выполняется за условно константное время независимо от общего объема коллекции. В худшем случае (при высокой плотности коллизий, когда разные ключи попадают в одну корзину) сложность может стремиться к O(N), однако при штатном распределении ключей вероятность подобного сценария минимальна.
  2. Индексированная ТаблицаЗначений: Индекс платформы 1С для колонок таблицы значений строится на основе древовидных структур данных (деревьев поиска). Поиск через НайтиСтроки() по проиндексированным колонкам выполняется за логарифмическое время — O(log N).
  3. Неиндексированные коллекции (для сравнения): Поиск по неиндексированной таблице значений или в объекте СписокЗначений требует полного последовательного перебора элементов, что дает линейную сложность O(N).

Таким образом, с точки зрения чистой алгоритмической сложности точечный поиск одиночного значения по ключу в объекте Соответствие быстрее, особенно по мере увеличения количества элементов в выборке.

Особенности синтаксиса и проверка наличия элементов

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


// Простое получение значения из кэша
ЗначениеКэша = Кэш[ИскомыйКлюч];
Если ЗначениеКэша = Неопределено Тогда
    // Внимание: логика может сработать некорректно, если в кэше хранится само Неопределено!
КонецЕсли;

Проанализируем эту ситуацию: если коллекция Соответствие содержит ключ, значением которого явно является Неопределено, проверка через прямое чтение индексатора не позволит отличить реальное отсутствие ключа от присутствия ключа со значением по умолчанию. У Соответствия нет встроенного метода быстрой проверки наличия ключа, и гарантированно определить его существование можно только полным перебором. Если требуется строгая проверка факта присутствия строкового идентификатора, альтернативой может выступать объект Структура с методом Свойство():


ЗначениеКэша = Неопределено;
Если СтруктураКэша.Свойство(ИмяКлюча, ЗначениеКэша) Тогда
    // Ключ гарантированно присутствует в коллекции
КонецЕсли;

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


Отбор = Новый Структура("Артикул", ИскомыйАртикул);
НайденныеСтроки = ТаблицаЦен.НайтиСтроки(Отбор);

Если НайденныеСтроки.Количество() > 0 Тогда
    СтрокаДанных = НайденныеСтроки[0];
КонецЕсли;

Регистрозависимость и типы ключей

Важнейшее практическое различие между коллекциями заключается в способе сравнения ключей строкового типа:

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

Затраты на запись, перестроение индексов и расход памяти

Сравним накладные расходы при наполнении коллекций и потреблении оперативной памяти:

  1. Потребление памяти: ТаблицаЗначений — тяжеловесный объект. Она хранит структуру колонок, строки таблицы, метаданные типов и сам индекс. Объект Соответствие расходует в разы меньше оперативной памяти при сопоставимом объеме хранимых пар ключ-значение.
  2. Оптимальный порядок индексации таблицы: Если добавить индекс в коллекцию Индексы до заполнения строк, то каждый последующий вызов Добавить() или ЗаполнитьЗначения() вызовет моментальное перестроение дерева индекса. Это кардинально замедлит наполнение таблицы. При работе с таблицей значений всегда применяем правильный паттерн: сначала заполняем все данные, и только затем создаем индекс перед началом серии поисков:

// Правильный сценарий работы с индексами ТаблицыЗначений:
ТаблицаЦен = Новый ТаблицаЗначений;
ТаблицаЦен.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТаблицаЦен.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));

// 1. Сначала наполняем таблицу данными
Для Каждого СтрДанных Из ИсточникДанных Цикл
    НоваяСтрока = ТаблицаЦен.Добавить();
    НоваяСтрока.Номенклатура = СтрДанных.Номенклатура;
    НоваяСтрока.Цена = СтрДанных.Цена;
КонецЦикла;

// 2. Только после наполнения создаем индекс
ТаблицаЦен.Индексы.Добавить("Номенклатура");

Составные ключи и множественный результат

Выбор структуры зависит от сложности критериев поиска:

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

Контекст выполнения (клиент-сервер)

Разберем ограничения сред выполнения:

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

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

Подведем практический итог для выбора инструмента:

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