К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как индексировать в запросе 1С: практическое руководство

Как индексировать временные таблицы в запросе 1С: синтаксис ИНДЕКСИРОВАТЬ ПО, когда индекс ускоряет запрос, типичные ошибки и проверка результата.

Конструкция ИНДЕКСИРОВАТЬ ПО в языке запросов 1С создаёт индекс для временной таблицы, помещённой во временное хранилище менеджера временных таблиц. Индекс ускоряет соединения и условия отбора по проиндексированным полям в последующих запросах пакета, но не влияет на таблицы базы данных — их индексы создаются только в конфигураторе.

Механизм работает так: первый запрос пакета выбирает данные и помещает их во временную таблицу с указанием индексируемых полей, а второй и последующие запросы соединяются с этой таблицей или фильтруются по ней. Без индекса платформа сканирует временную таблицу полностью при каждом обращении, что на больших объёмах приводит к заметным задержкам.

Важно понимать границы применимости: индексирование оправдано только для временных таблиц с существенным количеством строк, которые используются в соединениях или условиях дальше по пакету. На маленьких выборках накладные расходы на построение индекса могут превысить выигрыш.

Где именно в запросе 1С применяется индексирование

Конструкция ИНДЕКСИРОВАТЬ ПО допустима только в запросах, которые создают временную таблицу, то есть содержат предложение ПОМЕСТИТЬ. Индекс строится по указанным полям в момент выполнения запроса и живёт вместе с временной таблицей до уничтожения менеджера временных таблиц или явного удаления таблицы запросом УНИЧТОЖИТЬ.

Типичный сценарий — пакетный запрос из двух и более частей: сначала отбираются данные в ВТ_Данные, затем она соединяется с регистрами или другими временными таблицами. Если соединение идёт по полю, которое не входит в индекс, платформа выполнит полный перебор строк временной таблицы.

К таблицам базы данных — справочникам, документам, регистрам — ИНДЕКСИРОВАТЬ ПО неприменимо. Их индексы задаются в конфигураторе: свойство «Индексировать» у реквизита, индексы измерений регистров, автоматические индексы по ссылкам и стандартным реквизитам.

Синтаксис ИНДЕКСИРОВАТЬ ПО с примером

Секция ИНДЕКСИРОВАТЬ ПО располагается после ПОМЕСТИТЬ и перечисляет одно или несколько полей через запятую. Порядок секций в запросе фиксирован: выборка, ПОМЕСТИТЬ, ИНДЕКСИРОВАТЬ ПО, УПОРЯДОЧИТЬ ПО (если нужна сортировка).

ВЫБРАТЬ

Продажи.Номенклатура КАК Номенклатура,

СУММА(Продажи.Количество) КАК Количество

ПОМЕСТИТЬ ВТ_Продажи

ИЗ

РегистрНакопления.Продажи.Обороты(&Начало, &Конец, , ) КАК Продажи

СГРУППИРОВАТЬ ПО

Продажи.Номенклатура

ИНДЕКСИРОВАТЬ ПО

Номенклатура

;

ВЫБРАТЬ

Товары.Ссылка,

ВТ_Продажи.Количество

ИЗ

Справочник.Номенклатура КАК Товары

ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Продажи КАК ВТ_Продажи

ПО Товары.Ссылка = ВТ_Продажи.Номенклатура

Здесь индекс по полю Номенклатура позволяет второму запросу быстро находить строки временной таблицы при соединении, вместо полного перебора. В качестве индексируемого указывается псевдоним поля из списка выборки, а не исходное имя реквизита.

bsl
ВЫБРАТЬ Т.Контрагент, Т.Сумма ПОМЕСТИТЬ ВТ_Данные ИЗ ... ИНДЕКСИРОВАТЬ ПО Контрагент

Какие поля стоит индексировать

Индексировать нужно те поля, которые реально участвуют в условиях поиска по временной таблице: поля соединения (ПО Т1.Поле = Т2.Поле), поля из условий ГДЕ и В при обращении к временной таблице, поля вложенных запросов, фильтрующих выборку.

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

Не индексируйте поля «про запас»: каждый лишний индекс — это время на его построение и расход памяти. Поля с низкой селективностью (например, булево или признак с двумя значениями) в качестве единственного индекса почти не дают выигрыша.

Маршрут решения

Как выбрать поля для индекса

Временная таблица соединяется с другой по одному полюИндексируйте это поле соединения
Соединение идёт по двум-трём полям одновременноВключите все поля соединения в один составной индекс
Временная таблица только перебирается целиком в итоговой выборкеИндекс не нужен — он не даст выигрыша
По временной таблице есть условие ГДЕ или В в следующем запросеИндексируйте поля из этого условия

Когда индекс реально ускоряет, а когда вредит

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

На маленьких таблицах — десятки или сотни строк — построение индекса занимает время, а поиск и так выполняется быстро полным перебором. В этом случае ИНДЕКСИРОВАТЬ ПО замедляет выполнение пакета, хотя и незначительно.

Ещё одна ситуация, где индекс бесполезен: временная таблица создаётся и сразу выбирается целиком в конечный результат без соединений и фильтров. Индекс здесь не будет использован ни разу.

Индексы таблиц базы данных: что делается в конфигураторе

Часто под «индексированием в запросе» подразумевают другую задачу: запрос к регистру или справочнику работает медленно, и нужно ускорить выборку на уровне СУБД. Здесь запрос бессилен — индексы физических таблиц создаются в конфигураторе.

Основные инструменты: свойство «Индексировать» у реквизита объекта (варианты «Индексировать» и «Индексировать с доп. упорядочиванием»), автоматическое индексирование измерений регистров, входящих в отборы виртуальных таблиц, индексы по ссылке, дате и номеру, которые платформа создаёт сама.

Практическое правило: реквизит стоит индексировать, если по нему регулярно выполняется поиск, отбор или соединение в типовых операциях, и таблица достаточно велика. Массовое включение индексации у всех реквизитов увеличивает размер базы и замедляет запись, поэтому решение принимают по реальным узким местам, выявленным замером производительности.

Как проверить, что индекс используется

Прямого инструмента «показать план запроса» для временных таблиц в типовой консоли нет, поэтому проверка строится на замерах: выполните пакетный запрос с ИНДЕКСИРОВАТЬ ПО и без него на реальных объёмах данных и сравните время выполнения. Разница должна быть устойчивой при повторных запусках, а не случайной флуктуацией.

Для запросов к таблицам базы данных используйте технологический журнал с событиями СУБД и планы запросов на стороне MS SQL Server или PostgreSQL: там видно, идёт поиск по индексу (Index Seek) или полное сканирование (Seq Scan / Clustered Index Scan).

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

Контрольные точки

Как проверить результат

Время выполнения пакетного запроса
Норма

Заметно сократилось на реальных объёмах

Тревожный признак

Не изменилось или выросло — индекс не используется или лишний

Поле в ИНДЕКСИРОВАТЬ ПО
Норма

Совпадает с полем соединения или условия

Тревожный признак

Индекс по одному полю, а соединение — по другому

План запроса на СУБД для таблиц БД
Норма

Index Seek по нужному индексу

Тревожный признак

Полное сканирование таблицы

Типичные ошибки при индексировании

Самая частая ошибка — индексировать поле, которое не участвует в соединении или отборе. Например, временная таблица индексируется по сумме, а соединяется по номенклатуре: индекс построен, но платформа его не использует.

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

Третья группа ошибок — ожидание эффекта там, где его не может быть: индексирование мелкой временной таблицы, попытка применить ИНДЕКСИРОВАТЬ ПО к таблице базы данных, надежда, что индекс в запросе исправит отсутствие индекса в конфигураторе.

Типичные ошибки
01
Индекс по полю, которое не используется в соединении — индекс построен, но не применяется
02
Несовпадение типов полей в условии соединения — индекс отключается
03
Индексирование таблицы из нескольких десятков строк — лишние накладные расходы
04
Ожидание, что ИНДЕКСИРОВАТЬ ПО ускорит запрос к таблице базы данных — она работает только с временными таблицами
05
Индексация всех полей подряд — рост времени построения и расхода памяти без выигрыша

Практический порядок оптимизации медленного запроса

Действуйте от замера, а не от предположений. Сначала выясните, какая часть пакетного запроса занимает время: создание временных таблиц или финальная выборка с соединениями. Затем проверьте, есть ли индексы по полям соединений — во временных таблицах через ИНДЕКСИРОВАТЬ ПО, в таблицах базы данных через конфигуратор.

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

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

Что важно запомнить

ИНДЕКСИРОВАТЬ ПО применяется только к временным таблицам и только по полям соединений и отборов. Эффект проверяется замером на реальных объёмах. Индексы таблиц базы данных настраиваются в конфигураторе, а их использование — через план запроса на СУБД.

Частые вопросы

Можно ли проиндексировать таблицу значений, переданную в запрос как параметр?

Да, но не напрямую. Таблица значений передаётся параметром, помещается во временную таблицу запросом с ПОМЕСТИТЬ, и уже в этом запросе указывается ИНДЕКСИРОВАТЬ ПО по нужным полям. Дальнейшие соединения с этой временной таблицей будут использовать индекс.

Работает ли ИНДЕКСИРОВАТЬ ПО без ПОМЕСТИТЬ?

Нет. Конструкция синтаксически допустима только в запросах, создающих временную таблицу. В обычном запросе выборки она бессмысленна, поскольку результат сразу возвращается и индексировать нечего.

Сколько полей можно указать в ИНДЕКСИРОВАТЬ ПО?

Можно перечислить несколько полей через запятую — будет построен составной индекс. Практический предел определяется здравым смыслом: каждое дополнительное поле увеличивает время построения индекса и расход памяти, поэтому включайте только поля, реально участвующие в поиске.

Почему запрос с индексом всё равно медленный?

Частые причины: индекс построен не по тому полю, типы данных в условии соединения различаются, временная таблица мала и узкое место в другом, либо основное время уходит на выборку из таблиц базы данных, где нужен индекс уровня конфигуратора. Проверяйте замером по частям пакета.

Чем ИНДЕКСИРОВАТЬ ПО отличается от свойства «Индексировать» у реквизита?

ИНДЕКСИРОВАТЬ ПО создаёт временный индекс в памяти на время жизни менеджера временных таблиц и управляется из текста запроса. Свойство «Индексировать» у реквизита создаёт постоянный индекс в базе данных и настраивается в конфигураторе с последующей реструктуризацией.

Нужно ли удалять временные таблицы после использования?

Желательно. Запрос УНИЧТОЖИТЬ ВТ_Данные освобождает память, занятую таблицей и её индексами, что важно в длительных пакетах с несколькими крупными временными таблицами. Если таблицы не удалять, они живут до закрытия менеджера временных таблиц.