PostgreSQL — мощная СУБД, но даже опытные разработчики сталкиваются с медленными запросами. В этой статье разбираем, как анализировать план выполнения через EXPLAIN ANALYZE, находить узкие места и применять конкретные оптимизации — от индексов до пересмотра JOIN’ов. Практические примеры и чеклист помогут ускорить ваши SQL-запросы в Rails-приложениях.
Ты написал EXPLAIN (ANALYZE, BUFFERS) — и получил страшное древо планов.
Как из этого перейти к реальной оптимизации?
Вот краткий чеклист и расшифровка шагов.
🕵️ Шаг 1. Посмотри на первый узел
Первая строка плана — ключевая:
Nested Loop (actual time=...)
📌 Если тут Seq Scan, Nested Loop, rows=100000 — потенциальная беда.
Ищи, на что приходится максимальное actual time и loops=...
📚 Шаг 2. Пойми где и что сканируется
Seq Scanна таблице с миллионами строк? 💣Index Scan, но очень многоloops=...? 🔁Bitmap Heap Scanс много read? 💾
💡 Сравни rows (оценка) и actual rows — если они сильно отличаются, Postgres ошибается в предположениях.
🛠 Используй ANALYZE для обновления статистики.
📦 Шаг 3. Посмотри на BUFFERS
Buffers: shared hit=400 read=800
- read > hit → данные с диска → медленно
- dirtied → ты что-то пишешь (удивительно?)
🔄 Шаг 4. Проверь порядок JOIN‘ов
Если Nested Loop + внутренняя таблица большая — это ловушка.
Поменяй порядок таблиц (JOIN в другом порядке) или заставь использовать Hash Join (например, через enable_nestloop = off временно).
🧠 Шаг 5. Подумай: нужен ли тебе подзапрос?
SELECT * FROM users WHERE id IN (
SELECT user_id FROM posts WHERE ...
)
→ Медленно, особенно если IN (...) длинный.
🛠 Лучше JOIN, EXISTS или CTE.
💡 Советы по оптимизации
| Проблема | Что делать |
|---|---|
Seq Scan |
Добавить индекс |
Nested Loop + много rows |
Попробовать Hash Join |
read > hit |
Увеличить work_mem, пересмотреть логику |
Bitmap Heap Scan |
Оптимизировать фильтры и индексы |
Нет Index Scan |
Добавить индекс, уточнить условие |
🧪 Как тестировать изменения
- Напиши изначальный запрос
- Сделай
EXPLAIN (ANALYZE, BUFFERS) - Измени (JOIN, индексы, LIMIT, фильтры)
- Снова
EXPLAIN - Сравни время, read/hit, план
💬 Подсказка: используешь Postgres ≥13? Можно копировать план из pgAdmin, а можно вставлять его в https://explain.dalibo.com/ — и он покажет всё наглядно.