Индекс — это не бесплатное ускорение. Каждая запись в таблицу теперь пишет ещё и в индекс, а на диске индекс занимает место, сопоставимое с самой таблицей.

Когда индекс действительно нужен#

  • Поле часто участвует в WHERE, JOIN или ORDER BY.
  • Таблица достаточно большая, чтобы последовательное сканирование было заметно дороже.
  • Селективность высокая — индекс по полю status с тремя значениями почти бесполезен.
explain.sql
EXPLAIN ANALYZE
SELECT * FROM posts
WHERE status = 'published'
  AND published_at <= now()
ORDER BY published_at DESC
LIMIT 12;

Не добавляйте индекс, потому что «так надёжнее». Добавляйте, потому что EXPLAIN это подтвердил.

— внутренний код-ревью гайд
Тип индексаХорош дляПлох для
B-treeравенство, диапазоны, сортировкаполнотекстовый поиск
GINJSONB, массивы, полнотекстчастые обновления строки
Частичныйузкий фильтр (например, status)запросы без этого условия

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

Ключевые выводы

  • Индекс ускоряет чтение и замедляет запись — добавлять его «на всякий случай» нельзя.
  • B-tree подходит для равенства и диапазонов, GIN — для JSONB и полнотекстового поиска.
  • EXPLAIN ANALYZE — обязательный шаг перед добавлением индекса, а не после.
  • Частичные индексы экономят место, если запросы всегда фильтруют по одному условию.