PostgreSQL — мощная СУБД, но без понимания планов выполнения запросов даже опытные разработчики сталкиваются с неожиданными тормозами. В этой статье разберём основные типы JOIN-операций (Nested Loop, Hash Join, Merge Join) и методы доступа к данным (Index Scan, Seq Scan, Bitmap Scan), которые влияют на производительность Rails-приложений. Узнаем, как читать вывод EXPLAIN ANALYZE и оптимизировать запросы с учётом статистики, индексов и настроек work_mem.
Когда ты смотришь на EXPLAIN ANALYZE, первое чувство — легкое замешательство.
Вот краткий словарь, который поможет читать планы PostgreSQL с первого взгляда.
🔁 Nested Loop
Цикл в цикле: для каждой строки из внешней таблицы выполняется поиск во внутренней.
Nested Loop
-> Seq Scan on orders
-> Index Scan on users ...
🚨 Медленно, если строк много. Может выполнить 1000+ отдельных запросов.
🛠 Спасает LIMIT, индексы, анализ размера выборки.
🧠 Hash Join
Вместо перебора — Postgres строит хеш-таблицу по одной из таблиц и быстро ищет совпадения.
Hash Join
-> Seq Scan on users
-> Hash
-> Seq Scan on orders
📌 Отлично работает при большом количестве строк, если есть память.
📚 Merge Join
Обе таблицы отсортированы, и Postgres идёт по ним одновременно как merge в merge-sort.
Merge Join
-> Index Scan on users
-> Index Scan on orders
⚡ Быстро, если таблицы уже отсортированы по join-ключу.
🔍 Index Scan
Идеально: Postgres использует индекс, чтобы найти только нужные строки.
Index Scan using users_pkey on users
📌 Быстро, если фильтр попадает по индексу.
👣 Seq Scan
Постгрес читает всю таблицу целиком.
Seq Scan on users
🚨 Бывает быстро (если мало строк) или ужасно медленно (если таблица большая).
🧮 Bitmap Index Scan
Промежуточный вариант между Index Scan и Seq Scan. Сначала собираются ссылки, потом идут за данными.
Bitmap Heap Scan on users
-> Bitmap Index Scan on index_users_on_email
📌 Хорошо работает, когда условие даёт много совпадений.
🧰 Что влияет на выбор плана
- Размер выборки
- Наличие и состав индексов
- Статистика (ANALYZE!)
- Настройки памяти (
work_mem) - Связанные условия
JOIN,WHERE
🧭 Запомни
| Термин | Что это | Когда быстро |
|---|---|---|
| Nested Loop | Цикл в цикле | Мало строк, быстрый индекс |
| Hash Join | Хеш-таблица | Много строк, хорошее распределение |
| Merge Join | Сортированные источники | Есть индекс по join-полю |
| Seq Scan | Чтение всей таблицы | Маленькая таблица или нет индекса |
| Index Scan | Точное попадание по индексу | Хорошие индексы |
| Bitmap Index Scan | Много совпадений, сжатый поиск | Альтернатива Seq Scan для индекса |