Сделал EXPLAIN — и что дальше? Как оптимизировать SQL-запрос

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 Добавить индекс, уточнить условие

🧪 Как тестировать изменения

  1. Напиши изначальный запрос
  2. Сделай EXPLAIN (ANALYZE, BUFFERS)
  3. Измени (JOIN, индексы, LIMIT, фильтры)
  4. Снова EXPLAIN
  5. Сравни время, read/hit, план

💬 Подсказка: используешь Postgres ≥13? Можно копировать план из pgAdmin, а можно вставлять его в https://explain.dalibo.com/ — и он покажет всё наглядно.

🗓 Дата публикации: 22.01.2025, но это не точно...

PostgreSQL SQL оптимизация запросов EXPLAIN ANALYZE индексы JOIN