Короткий ответ
Сначала получают план выполнения через EXPLAIN ANALYZE, чтобы увидеть, использует ли запрос индекс или делает полное сканирование таблицы, затем по результатам добавляют подходящий индекс, переписывают запрос или пересматривают постраничную выборку, вместо того чтобы оптимизировать вслепую.
Как это работает подробнее
EXPLAIN ANALYZE показывает реальный план и время выполнения каждого узла запроса в PostgreSQL; Seq Scan на большой таблице там, где ожидался Index Scan, обычно означает отсутствие подходящего индекса или то, что условие в WHERE не позволяет его использовать (например, функция поверх индексируемого столбца).
Пример кода
query.sql
EXPLAIN ANALYZE
SELECT * FROM orders
WHERE customer_id = 42 AND status = 'active'
ORDER BY created_at DESC
LIMIT 20;
-- Seq Scan on orders (cost=0.00..185000.00 rows=120 actual time=3980.00..4000.00)
CREATE INDEX idx_orders_customer_status_created
ON orders (customer_id, status, created_at DESC);
-- Новый план использует Index Scan и возвращает страницу за миллисекундыЧто использовать на практике
- Практика. Типичные находки — отсутствие составного индекса под часто используемый фильтр+сортировку, OFFSET с большим значением при постраничной навигации (лучше заменить на keyset pagination по последнему ID/дате), неэффективный JOIN с большой промежуточной таблицей без фильтрации заранее.
Подводные камни
- Риск. Добавляют индекс на каждый столбец из WHERE без учёта селективности и порядка столбцов в составном индексе; оптимизируют один запрос, не замечая, что похожий паттерн используется ещё в нескольких местах; не перепроверяют план после изменения.