Ответ
Да, это классическая проблема, с которой сталкивался многократно, особенно при работе с ORM.
Проблема N+1 возникает, когда для получения списка сущностей (N) и связанных с каждой из них данных выполняется один основной запрос и N дополнительных запросов. Это убивает производительность.
Пример на SQLAlchemy (Python):
# ПЛОХО: N+1 запросов
users = session.query(User).all() # 1 запрос: SELECT * FROM users
for user in users:
# Для КАЖДОГО пользователя выполняется отдельный запрос
print(user.orders) # N запросов: SELECT * FROM orders WHERE user_id = ?
# ХОРОШО: Eager Loading (жадная загрузка) одним запросом с JOIN
from sqlalchemy.orm import joinedload
users = session.query(User).options(joinedload(User.orders)).all()
# Выполняется 1 запрос: SELECT * FROM users LEFT JOIN orders ON ...
for user in users:
print(user.orders) # Данные уже загружены в память
Способы решения, которые я применял:
- Жадная загрузка (Eager Loading): Использование
joinedloadв SQLAlchemy,Include()в Entity Framework,.with()в Laravel Eloquent. - Явные JOIN в запросе: Иногда эффективнее написать raw SQL или QueryBuilder с явным указанием связей.
- Выборка только нужных полей (Projection): Вместо загрузки целых объектов — выборка только необходимых колонок.
- Кэширование: Если данные редко меняются, результат сложного запроса можно закэшировать.
Обнаруживаю такие проблемы с помощью мониторинга логов медленных запросов (например, в PostgreSQL log_min_duration_statement) и профилирования ORM.