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

Полный перебор: как база ищет без индекса

Выполняя SELECT * FROM orders WHERE customer_id = 42, база по умолчанию делает ровно то, что делали бы вы с бумажной книгой без оглавления: читает всё подряд и откладывает подходящее. Это называется полным перебором (sequential scan). На тысяче строк он незаметен, на ста миллионах — это минуты работы дисков.

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

Индекс — оглавление таблицы

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

Есть индекс по customer_id — запрос WHERE customer_id = 42 находит строки за доли секунды независимо от размера таблицы. Нет — полный перебор.

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

Когда индекс есть, но не работает

Коварный класс ситуаций — индекс существует, а запрос всё равно перебирает всю таблицу:

  • Функция над столбцом. WHERE lower(email) = 'anna@...' — индекс построен по email, а сравнивается lower(email), для базы это другое выражение. Тот же эффект у арифметики: WHERE amount * 100 > 5000.
  • LIKE с процентом в начале. LIKE 'anna%' индексом пользуется (как поиск по первым буквам в алфавитном указателе), а LIKE '%@gmail.com' — нет: по «окончанию слова» оглавление не работает.
  • Слабая избирательность. WHERE status = 'paid', когда оплачены 90 % заказов: проще прочитать всю таблицу, чем прыгать по ссылкам на почти каждую строку. База сама выбирает перебор — и это правильное решение.

EXPLAIN: спросить базу, как она будет искать

Гадать не нужно — базу можно спросить. Добавьте перед запросом слово EXPLAIN:

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

Вместо данных база покажет план: как она собирается выполнять запрос. Читать планы глубоко — отдельное искусство, но первый уровень доступен сразу: увидели Seq Scan (последовательный перебор) на большой таблице — вот причина тормозов; Index Scan — работает индекс. Этого достаточно, чтобы разговор с разработчиком начался не с «что-то тормозит», а с «поиск заказов по номеру телефона идёт полным перебором, таблица 40 миллионов строк».

Где это применяется

Это знание работает в обе стороны. Внутрь — про ваши запросы: тяжёлый SELECT без ограничений по огромной таблице на общем стенде мешает всем; добавьте LIMIT и условия по индексированным полям. Наружу — про продукт: «поиск в приложении отвечает 40 секунд» — это дефект производительности, и после EXPLAIN вы опишете его на уровне причины, а не симптома. А фраза разработчика «там нет индекса» перестанет быть заклинанием — вы понимаете, что она значит и чем грозит.

Где спотыкаются начинающие:

  • Меряют скорость на пустом стенде. Сто строк летают без всяких индексов; выводы о производительности с маленькой базы не переносятся на большую.
  • Считают, что индекс ускоряет всё. Индекс помогает конкретным условиям поиска — и берёт плату замедлением записи. «Добавьте индексов» — не универсальный рецепт.
  • Пишут условия, убивающие индекс, — функции над столбцом, LIKE с процентом в начале — и удивляются перебору.

Что учить дальше. Цикл «SQL с нуля» пройден. Практическое применение в работе тестировщика — в статье SQL для тестировщика. А когда захочется глубины — раздел PostgreSQL: транзакции и изоляция, устройство индексов, EXPLAIN всерьёз.