N+1 без единой строчки кода

На собеседовании вопрос часто формулируют без кода вовсе: «как найти N+1 в проде, если доступа к коду нет». Проверяют не знание ORM, а умение читать систему со стороны — через метрики и логи, а не через ревью.

Первый признак — количество запросов к БД растёт линейно с размером ответа API. Если эндпоинт вернул список из 50 заказов и сделал 51 запрос вместо двух — это почти наверняка N+1: один запрос на список, и ещё по одному на каждую связанную сущность.

Второй признак — одинаковый шаблон запроса повторяется много раз подряд с разными значениями параметра. В логе медленных запросов PostgreSQL (log_min_duration_statement) или в выводе APM-трейса это видно как частокол одинаковых SELECT с разным id в WHERE.

Третий способ — включить логирование запросов на уровне ORM-сессии в staging и посмотреть на один HTTP-запрос: если на один вызов эндпоинта приходится десятки SQL-запросов к одной и той же таблице — паттерн найден без единой строчки бизнес-кода.

Что спросят следом: «а как починить, если JOIN FETCH или select_related невозможны из-за архитектуры (данные в разных сервисах)?» Ответ — батчинг через IN (...) вместо JOIN: собрать все id, сделать один запрос с условием id IN (список), и замаппить результат в памяти. Это общий приём независимо от ORM и даже независимо от того, одна это база или разные сервисы.

N+1 — это паттерн в трафике к БД, а не ошибка в конкретной строке кода, поэтому его ищут метриками, а не отладчиком.

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки