← вся теориятеория к собесу · Оптимизация запросов 1С

Индексы и план запроса в 1С

разбор писал Даниил, автор Сеньорчика

Зачем это спрашивают

Индекс ускоряет поиск, если запрос может им воспользоваться. В 1С индексы задают флагами метаданных, а решает, использовать ли их, СУБД (система управления базами данных) по статистике. Ниже планы PostgreSQL 16 на таблице в 200 000 строк: какой отбор идёт по индексу, а какой нет.

// Так спрашивают: «Что делает флаг Индексировать?» «Зачем «Индексировать с доп. упорядочиванием»?» «Сработает ли составной индекс при отборе по второму полю?» «Почему индекс по булеву полю не помогает?»

Индексы из метаданных

Флаг «Индексировать» у реквизита создаёт индекс СУБД по этому полю, и платформа добавляет в него ссылку. Уникальности индекс не даёт: два элемента с одинаковым артикулом запишутся. Вариант «Индексировать с доп. упорядочиванием» добавляет в индекс поле сортировки, и динамический список, который отбирает по реквизиту и сортирует по наименованию, читает порции прямо по индексу.

Индексы создают метаданными, а не руками в СУБД: при реструктуризации платформа пересоздаёт таблицы, и ручной индекс пропадёт. Измерения регистров индексируются платформой сами, порядок измерений задаёт порядок полей индекса.

Составной индекс

Составной индекс работает по первым полям. Индекс по товару и складу помогает отбору по товару, а отбор только по складу пойдёт мимо. Таблица на 200 000 строк, индекс по (товар, склад):

По товару СУБД пошла по индексу (Index Scan): нашла ключ и прочитала одну строку. По складу индекс начинается не с того поля, и СУБД читает таблицу целиком (Seq Scan), проверяя условие на каждой строке. В терминах MS SQL это Seek и Scan.

Для 1С отсюда правило порядка измерений регистра: первыми ставят те, по которым отбирают чаще всего. Регистр с измерениями «склад, товар» плохо отвечает на вопрос «где лежит этот товар».

EXPLAIN (COSTS OFF)
SELECT price FROM prices WHERE item = 777;
EXPLAIN (COSTS OFF)
SELECT price FROM prices WHERE store = 7;

Избирательность и статистика

Индекс полезен, когда условие отбирает малую долю строк. Флаг акции стоит у 1% товаров, по нему есть индекс. Отбор «по акции» и «не по акции»:

Для редкого значения индекс сработал, для частого СУБД читает таблицу целиком: 99% строк всё равно придётся прочитать, и прыжки по индексу только добавят работы. Индекс по полю, где почти все значения одинаковы, ускоряет только поиск редкого значения, а писать в таблицу становится дороже: каждая запись обновляет и индекс.

Решение «индекс или полное чтение» СУБД принимает по статистике распределения значений. После загрузки миллиона документов статистика устаревает, и старые планы деградируют. Её обновляют регламентом обслуживания, иначе хороший индекс перестаёт выбираться.

EXPLAIN (COSTS OFF)
SELECT price FROM prices WHERE promo;
EXPLAIN (COSTS OFF)
SELECT price FROM prices WHERE NOT promo;

Как отвечать: «Добавили флаг Индексировать на реквизит, а запрос не ускорился. Почему?»

Причин несколько. Условие может не пользоваться индексом: функция над полем, ПОДОБНО с процентом в начале, отбор не по первому полю составного индекса. Поле может быть малоизбирательным, и СУБД разумно выбирает полное чтение. Статистика может быть старой, тогда план не учитывает новый индекс. Проверяю план запроса в СУБД и смотрю, есть ли там поиск по индексу или полное чтение таблицы.

Ответ перебирает причины от кода к СУБД и заканчивается проверкой по плану. Это показывает, что кандидат не верит флагу на слово.

На чём валят

  • −Ждут уникальности от флага Индексировать. Индекс не уникальный. Уникальность проверяют кодом или запросом.
  • −Индексируют булево поле, где 99% значений одинаковы. По частому значению индекс не помогает, а запись дорожает.
  • −Отбирают по второму полю составного индекса. Индекс читается целиком или не используется. Порядок полей под частые отборы.
  • −Не обновляют статистику после массовой загрузки. Планы деградируют. Статистику обновляют регламентом.

Проверь себя

Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.

  1. #oc_q_indexes1 / 5
    Есть ли смысл индексировать булев реквизит «ЭтоАрхивный», если 99% записей — Ложь?
    A)Да: индекс ускорит отбор по Ложь
    B)Мало толку: поле малоизбирательно
    C)Да, если это первый реквизит справочника
    D)Нет: булевы реквизиты индексировать нельзя
    показать ответ и разбор
    +B)Мало толку: поле малоизбирательно

    // разбор: Индекс выгоден, когда отбор выбирает малую долю строк. По значению Ложь (99% строк) СУБД всё равно прочитает почти всю таблицу. Индекс пригодится только для редкой Истины, и то вместе с другими полями. Платформа индексировать булево поле позволяет.

  2. #oc_q_indexes2 / 5
    Зачем «Индексировать с доп. упорядочиванием»?
    A)Индекс включит поле сортировки
    B)Чтобы реквизит сортировался по убыванию
    C)Чтобы индекс попал в полнотекстовый поиск
    D)Чтобы индекс по реквизиту стал уникальным
    показать ответ и разбор
    +A)Индекс включит поле сортировки

    // разбор: Динамический список отбирает по реквизиту и сортирует по наименованию или коду. Обычный индекс содержит реквизит и ссылку, и сортировку приходится делать отдельно. Доп. упорядочивание добавляет в индекс основное поле упорядочивания (код, наименование, дату), и порции списка читаются по индексу.

  3. #oc_q_indexes3 / 5
    Индекс по (Товар, Склад). Какое условие использует его лучше всего?
    A)Товар = &Т И Склад = &С
    B)Склад = &С ИЛИ Товар = &Т
    C)ПОДСТРОКА(Товар.Код, 1, 3) = "А-1"
    D)Склад = &С
    показать ответ и разбор
    +A)`Товар = &Т И Склад = &С`

    // разбор: Составной индекс упорядочен по первому полю, затем по второму. Условие на оба поля или на первое ищет по индексу. Только по второму полю — индекс читается целиком. ИЛИ по разным полям и функции над полем мешают поиску.

  4. #oc_q_indexes4 / 5
    Какие индексы платформа создаёт у справочника без индексируемых реквизитов?
    A)Только по ссылке
    B)Ни одного: индексы создаёт администратор СУБД
    C)По каждому реквизиту
    D)По ссылке, коду и наименованию
    показать ответ и разбор
    +D)По ссылке, коду и наименованию

    // разбор: Платформа сама создаёт индексы по полям, которые нужны ей для типовых операций: по ссылке (кластерный), по коду и по наименованию, по родителю и владельцу при иерархии и подчинении. Индексы по прикладным реквизитам — только по свойству Индексировать.

  5. #oc_q_indexes5 / 5
    Администратор вручную добавил индекс в MS SQL на таблицу регистра. Что с ним будет?
    A)Он станет частью конфигурации после обновления
    B)Он ускорит все запросы базы автоматически
    C)Пропадёт при реструктуризации
    D)Платформа запретит его создать
    показать ответ и разбор
    +C)Пропадёт при реструктуризации

    // разбор: Платформа управляет структурой своих таблиц и при реструктуризации пересоздаёт их по метаданным. Ручные индексы при этом теряются, а их наличие не видно в конфигурации. Индексы задают свойствами метаданных; ручной индекс — временная мера с регламентом восстановления.

дальше

Теорию прочитал. Навык ставится повторением

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