главная/Проблема N+1 query

Проблема 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 users
  • SELECT * FROM posts WHERE user_id IN (...)

Когда ORM делает много мелких запросов (по одному на каждую запись), то:

  1. Каждый запрос тратит время на:
    • формирование SQL;
    • передачу его на сервер;
    • выполнение;
    • возврат результата;
    • ожидание сети.
  2. Эти накладные расходы суммируются.

Например:

  • 1 запрос выполняется за 2 мс;
  • 100 запросов = уже ~200 мс (вместо 5 мс, если бы всё выбрали одним JOIN’ом).