TGViewer
10 минут до кода 10 минут до кода @ten_minutes_to_code · 227 subscribers
Post #96 62
Иллюзия удобства: Как N+1 убивает ваш продакшн

Проблема N+1 — это классический «тихий убийца» производительности, на котором горят даже опытные разработчики. Мы привыкли доверять ORM, полагая, что под капотом всё уже оптимизировано за нас. Кажется, что достаточно вызвать метод и работать с данными как с обычными объектами языка. Но ORM — это всего лишь инструмент, и если использовать его вслепую, база данных ляжет быстрее, чем вы закончите код-ревью.

Механика деградации

Представим стандартную структуру: коллекция блюд, у каждого есть связь (relation) с категорией. Задача — отрисовать список блюд и для каждого вывести название его категории. Типичный сценарий: вы отправляете один запрос, загружаете продукты и начинаете перебирать их в цикле. Внутри цикла вы обращаетесь к свойству: product.category.

В коде это выглядит как обычный доступ к полю объекта. Но по факту данных там еще нет, потому что при первом запросе вы вытащили только продукты. Чтобы отдать вам категорию, ORM вынуждена «бегать» в базу на каждой итерации цикла.

Математика здесь беспощадна. У вас получается N + 1 запрос:

- 1 — первичный запрос на получение списка продуктов.
- N — количество дополнительных запросов, где N равно числу продуктов.

Если в списке 100 позиций — вы делаете 101 запрос. Если 1000 — 1001. Чем больше данных, тем сильнее вы нагружаете бэкэнд и СУБД инфраструктурным перегрузом: подготовкой SQL, установкой соединений и ожиданием ответов.

Логика «пустой банки»

Это похоже на уборку в квартире. Вы нашли пустую банку из-под колы, пачку от чипсов и какой-то фантик. Вместо того чтобы собрать весь мусор в один пакет и вынести его за раз, вы берете банку, идете к мусоропроводу, возвращаетесь, берете пачку, снова идете к мусоропроводу. Задача в итоге будет решена, мусор исчезнет, но вы потратите в пять раз больше времени на хождение по коридору, чем на саму уборку.

В разработке происходит то же самое. Вместо того чтобы сразу забрать нужные зависимости, вы заставляете систему тратить ресурсы на лишние итерации.

Инженерный подход к оптимизации

Современные ORM позволяют использовать Eager Loading (жадную загрузку). Вы просто указываете в запросе, какие связи нужно подтянуть сразу, в первом же запросе.

Если же инструмент этого не поддерживает, есть рабочий лайфхак:

1. Делаете один запрос на все продукты.
2. Делаете второй запрос на все категории, относящиеся к этим продуктам (через WHERE IN).
3. Сопоставляете данные уже в памяти приложения.

Это в разы быстрее, чем долбить базу мелкими запросами.

N+1 часто всплывает при рефакторинге: кто-то убрал подгрузку релейшна, код не упал (магия ORM же), но производительность рухнула. Исправление одной такой точки может ускорить API буквально в сотни раз.

Запомните правило: любой запрос в базу данных внутри цикла — это в 90% случаев архитектурный провал. Всегда загружайте данные до того, как начнете их перебирать.

Ставь 🔥, если ловил N+1 в логах только после того, как база начинала «дымиться» на проде. А если остались вопросы или что-то звучит слишком абстрактно — пиши в комменты, обязательно разберем!

10МДК | ВЕБМастер
  • 👍 5
  • 🔥 4
More from @ten_minutes_to_code
  1. May 28, 2026Первый сезон получился про путь “от пользователя к инженеру”. Именно эту картину мы весь с…
  2. May 28, 2026Когда я запускал этот канал, у меня была довольно простая идея: писать каждый день коротки…
  3. May 7, 2026Почему нормализация БД — это чистая логика, а не бюрократия На любом ongoing-проекте требо…
  4. May 3, 2026🤔 А где новые посты? Сори что вот так пропал без предупреждения, но я думал что справлюсь…
  5. Apr 29, 2026Почему HTTPS не спасет ваши секреты Замочек в адресной строке браузера — это мощное успоко…
  6. Apr 28, 2026Целостность данных против иллюзии атомарности Начинающий разработчик видит базу данных как…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →