Индекс — это не бесплатное ускорение. Каждая запись в таблицу теперь пишет ещё и в индекс, а на диске индекс занимает место, сопоставимое с самой таблицей.
Когда индекс действительно нужен#
- Поле часто участвует в
WHERE,JOINилиORDER BY. - Таблица достаточно большая, чтобы последовательное сканирование было заметно дороже.
- Селективность высокая — индекс по полю
statusс тремя значениями почти бесполезен.
EXPLAIN ANALYZE
SELECT * FROM posts
WHERE status = 'published'
AND published_at <= now()
ORDER BY published_at DESC
LIMIT 12;Не добавляйте индекс, потому что «так надёжнее». Добавляйте, потому что EXPLAIN это подтвердил.
— внутренний код-ревью гайд
| Тип индекса | Хорош для | Плох для |
|---|---|---|
| B-tree | равенство, диапазоны, сортировка | полнотекстовый поиск |
| GIN | JSONB, массивы, полнотекст | частые обновления строки |
| Частичный | узкий фильтр (например, status) | запросы без этого условия |
Частая ошибка
Композитный индекс (a, b) не используется для запросов только по b — порядок колонок в индексе имеет значение.
Итог простой: сначала EXPLAIN ANALYZE, потом индекс, потом снова EXPLAIN ANALYZE — чтобы убедиться, что план запроса действительно изменился.
Ключевые выводы
- Индекс ускоряет чтение и замедляет запись — добавлять его «на всякий случай» нельзя.
- B-tree подходит для равенства и диапазонов, GIN — для JSONB и полнотекстового поиска.
- EXPLAIN ANALYZE — обязательный шаг перед добавлением индекса, а не после.
- Частичные индексы экономят место, если запросы всегда фильтруют по одному условию.



