
Проблема N+1 query
Проблема N+1 — это типичная ошибка при работе с базой данных, особенно когда используется ORM (например, Eloquent, Doctrine и т.п.).
Она возникает, когда для выборки связанных данных выполняется много отдельных запросов, вместо одного оптимизированного.
Пример на PHP
$users = User::all(); // 1 запрос: SELECT * FROM users
foreach ($users as $user) {
echo $user->posts->count(); // для каждого юзера - ещё 1 запрос
}
Если в базе 100 пользователей — получится 101 запрос:
- 1 запрос, чтобы получить всех пользователей;
- +100 запросов, чтобы получить посты каждого.
Это и есть N+1 запрос (один основной + N дополнительных).
Как исправить
Использовать жадную загрузку (eager loading):
$users = User::with('posts')->get();
Теперь ORM выполнит всего 2 запроса
SELECT * FROM usersSELECT * FROM posts WHERE user_id IN (...)
Когда ORM делает много мелких запросов (по одному на каждую запись), то:
- Каждый запрос тратит время на:
- формирование SQL;
- передачу его на сервер;
- выполнение;
- возврат результата;
- ожидание сети.
- Эти накладные расходы суммируются.
Например:
- 1 запрос выполняется за 2 мс;
- 100 запросов = уже ~200 мс (вместо 5 мс, если бы всё выбрали одним JOIN’ом).