Читаем EXPLAIN ANALYZE в PostgreSQL
Когда запрос тормозит, первое, что стоит сделать, — посмотреть его план выполнения. EXPLAIN показывает, как планировщик собирается выполнять запрос, а EXPLAIN ANALYZE дополнительно выполняет его и показывает реальное время.
Seq scan против index scan
Возьмём таблицу на миллион строк и фильтр по email. Без индекса планировщик вынужден читать всю таблицу:
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'a@b.c';
-- Seq Scan on users (cost=0.00..18584 rows=1)
-- Filter: (email = 'a@b.c')
-- actual time=0.3..142 ms
Sequential scan на большой таблице — почти всегда повод задуматься. Добавим индекс:
CREATE INDEX idx_users_email ON users (email);
Теперь план меняется на Index Scan, и время падает на порядки — планировщик идёт по B-дереву вместо чтения всех страниц.
Почему индекс не используется
- Функция или приведение типа над колонкой: WHERE lower(email) = … не попадёт в обычный индекс по email — нужен индекс по выражению lower(email).
- LIKE с ведущим процентом: '%abc' не использует B-tree; помогает trigram-индекс (pg_trgm).
- Маленькая таблица: при нескольких сотнях строк seq scan дешевле, и это нормально.
Итог
Читайте план снизу вверх, обращайте внимание на узлы Seq Scan по крупным таблицам и на расхождение rows между оценкой и actual — это первый признак того, что статистика устарела и пора сделать ANALYZE.