сеньорчикОткрыть в Telegram
← блог
21 июля 2026 г.

Индексы в базе данных: как работают, когда помогают и почему иногда бесполезны

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

Разберём, как это работает на самом деле.

Зачем нужен

Без индекса база читает таблицу целиком и проверяет каждую строку. Миллион строк, из них подходит одна: прочитано будет всё равно всё.

Индекс это отдельная структура, где значения хранятся упорядоченно и рядом лежит ссылка на строку. Найти по ней нужное значение можно за несколько шагов вместо полного перебора.

Плата за скорость чтения: каждая вставка и обновление должны обновить ещё и индексы. Плюс место на диске.

B-tree: рабочая лошадка

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

Что из этого следует практически:

Работает на точном равенстве, на диапазонах, на сравнениях и на сортировке. Условие «дата больше такой-то» индекс использует прекрасно.

Работает на префиксе составного индекса. Индекс по паре (город, дата) поможет запросу с фильтром по городу, но не поможет запросу с фильтром только по дате. Классический вопрос на собеседовании.

Даёт отсортированный результат бесплатно, поэтому ORDER BY по индексированному полю не требует отдельной сортировки.

Другие типы

Хеш-индекс ищет только по точному равенству, зато очень быстро. Диапазоны и сортировка ему недоступны.

Полнотекстовый для поиска по словам в тексте, с учётом морфологии и ранжирования.

GIN и подобные для составных значений: массивы, JSON, полнотекстовый поиск в PostgreSQL.

Частичный индекс строится только по части строк, например только по активным заказам. Экономит место и обновляется дешевле.

Селективность: главное понятие

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

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

Почему индекс не используется

Пять типичных причин, и все встречаются в реальных проектах.

Функция над колонкой. Условие вида WHERE date(created_at) = '2026-07-21' убивает обычный индекс, потому что база не может сопоставить результат функции с хранимыми значениями. Лечится диапазоном по самой колонке или индексом по выражению.

Неявное приведение типов. Сравниваете строковую колонку с числом, и вместо индексного поиска получаете полный проход.

Низкая селективность. Смотри выше: база решила, что так дешевле.

Не тот префикс составного индекса. Индекс по (a, b), фильтр только по b.

Устаревшая статистика. Оптимизатор принимает решения по накопленным данным о распределении значений. После массовой загрузки статистику стоит обновить.

Проверяется всё это одним способом: посмотреть план запроса. В PostgreSQL это EXPLAIN, и умение его читать спрашивают на собеседованиях дата-инженеров и бэкендеров.

Покрывающий индекс

Отдельный приём, который стоит знать. Если в индекс входят все колонки, нужные запросу, база возьмёт данные прямо из индекса и не пойдёт в саму таблицу. Запрос ускоряется заметно.

Обратная сторона: индекс становится толще, обновления дороже. Приём хорош для конкретных горячих запросов, а не как привычка.

Сколько индексов вешать

Универсального числа нет, но есть здравые ориентиры.

Индексы под запросы, которые реально выполняются часто, а не под все возможные комбинации фильтров.

Составной индекс часто заменяет два отдельных, если порядок колонок выбран правильно.

Индексы под внешние ключи: без них удаление родительской строки может привести к полному проходу дочерней таблицы.

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

Отдельно про запись: на таблице, куда идёт поток вставок, каждый лишний индекс это налог на каждую вставку.

Что спрашивают на собеседовании

Как устроен B-tree и почему поиск быстрый. Когда индекс не поможет. Что такое селективность. Почему функция над колонкой ломает индекс. Как работает составной индекс и важен ли порядок колонок. Что такое покрывающий индекс. Как понять, использовался ли индекс.

Часто дают практический кейс: «запрос выполняется тридцать секунд, что будете делать». Ждут порядок действий: посмотреть план, найти полный проход, понять, есть ли подходящий индекс, проверить условия на предмет функций и типов, оценить селективность, и только потом что-то создавать.

Про то, как эти вопросы вписываются в общую картину баз данных, писали в разборе про реляционные базы, а практику по SQL собрали в задачах с собеседований.

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

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

Проверить себя вопросами можно в Сеньорчике: блоки по SQL, производительности запросов и хранилищам, вопросы с реальных собеседований с разбором каждого. Движок возвращает темы, где вы ошибаетесь. Десять минут в день в Telegram, бесплатно.