Вопрос оптимизации запросов через индексирование временных таблиц (ВТ) является одной из самых обсуждаемых тем среди разработчиков 1С. Часто возникает дилемма: индексировать все поля, участвующие в соединениях, или же создание индекса принесет больше вреда, чем пользы. В этой статье мы подробно разберем, как работают индексы во временных таблицах, проанализируем влияние различных типов данных и выясним, когда стоит накладывать индекс, а когда лучше от него отказаться.
Прежде чем приступать к индексации, необходимо понять «Принцип Меньшего Зла». Создание индекса — это не бесплатная операция. СУБД тратит ресурсы процессора на сортировку данных и дисковое пространство (в базе tempdb для MS SQL) на хранение структуры индекса. Рассмотрим основные правила, которыми стоит руководствоваться.
1. Правило «100 записей»
Согласно официальным рекомендациям 1С и опыту экспертов по технологическим вопросам, индексировать ВТ, в которой заведомо меньше 100 записей, бессмысленно. Для СУБД проще и быстрее выполнить полное сканирование таблицы (Full Scan), чем обращаться к дереву индекса. Если же количество записей превышает 1000, отсутствие индекса на полях соединения почти наверняка приведет к деградации производительности.
2. Частота использования ВТ в пакете
Проанализируем ситуацию: если временная таблица создается, а затем используется всего один раз в следующем запросе пакета, время на построение индекса может превысить выигрыш от его применения. Однако, если ВТ «тянется» через 10 и более последующих запросов, индекс становится критически важным.
Вернемся к примеру из вопроса. У нас есть поля: Ссылка (УИД), Номенклатурная группа (УИД), Вид (Перечисление) и Состав (Строка). Разберем каждое по отдельности.
Поля Ссылка и Номенклатурная группа являются лучшими кандидатами для индексации. В базе данных типа MS SQL они хранятся как binary(16) (128-битный GUID). Это компактный тип данных с очень высокой селективностью (уникальностью значений). Индексирование таких полей позволяет СУБД мгновенно находить нужные записи при соединении с другими таблицами.
Поле Вид (Перечисление) обычно имеет низкую селективность. Если у перечисления всего 3–5 значений, а в таблице 100 000 записей, индекс по этому полю будет практически бесполезен. СУБД все равно придется просматривать огромные блоки данных. Индексировать перечисления стоит только в том случае, если это единственное поле, по которому происходит соединение или жесткая фильтрация.
С полем Состав (тип Строка) нужно быть крайне осторожными. В 1С невозможно наложить индекс на строку неограниченной длины. На уровне СУБД такие поля имеют типы ntext или nvarchar(max), которые не поддерживают стандартное индексирование в 1С. Чтобы оптимизировать соединение по строке, необходимо предварительно привести её к фиксированной длине. Рассмотрим пример кода:
ВЫБРАТЬ
ВЫРАЗИТЬ(Т.Состав КАК СТРОКА(100)) КАК СоставКратко,
Т.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_Данные
ИЗ
Справочник.Номенклатура КАК Т
ГДЕ
Т.Ссылка В (&МассивСсылок)
ИНДЕКСИРОВАТЬ ПО
СоставКратко
;
Поведение оптимизатора запросов сильно зависит от используемой платформы:
Nested Loop (вложенные циклы), что на больших объемах данных приводит к «зависанию» запроса. Для Postgres индексация ВТ — это практически обязательное действие при соединениях.Hash Join, который эффективно работает и без индексов. Однако индекс дает оптимизатору более точные данные для построения идеального плана запроса.Важно помнить одну техническую особенность: в языке запросов 1С, в отличие от SQL, нельзя создать один составной индекс (по нескольким полям сразу) для временной таблицы. Если вы укажете:
ИНДЕКСИРОВАТЬ ПО Ссылка, НоменклатурнаяГруппа
Платформа создаст два отдельных индекса. СУБД в плане запроса выберет только один из них (наиболее селективный), а второй будет просто занимать ресурсы при создании таблицы. Поэтому рекомендуется индексировать только то поле, которое максимально однозначно идентифицирует запись в этой ВТ.
ПО ВТ1.Поле = ВТ2.Поле), индекс желателен. Если по неравенству — индекс обязателен.Ссылка или УИД.Разберем практическую ситуацию из сообщения 7 в обсуждении: на файловой базе запрос выполнялся 10 минут, а после добавления индекса — 15 секунд. Это наглядно доказывает, что в условиях ограниченных ресурсов СУБД (как в файловом варианте) правильная индексация является ключевым инструментом разработчика.
Таким образом, для задачи из сообщения 0 правильным решением будет наложить индекс на поле Ссылка или Номенклатурная группа, при условии, что данных в таблице достаточно много. Индексировать Вид не стоит из-за низкой селективности, а Состав — из-за ограничений на длину строк.