Монолит с отчётами на 30 секунд: как переписали архитектуру и что из этого вышло

В Django-монолите отчёты по филиалам открывались до 30 секунд из-за N+1, полного сканирования таблицы orders и логики, размазанной по контроллерам. Автор последовательно сократил нагрузку на базу, перестроил архитектуру и добавил quality gate для продакшена.

Разбор начался с EXPLAIN ANALYZE: отчёт по филиалу делал Seq Scan по таблице orders с 280 тысячами записей, ORM порождал N+1, а одна страница отправляла в базу 2800+ запросов. После замены обычных обращений к связанным объектам на select_related и prefetch_related число запросов сократилось до трёх, а затем составной индекс по branch_id и created_at и GIN-индекс для полнотекстового поиска убрали полный скан и перевели запрос на Index Scan.

Индекс создавали с CONCURRENTLY, чтобы не блокировать таблицу в продакшене. На этом фоне время выполнения конкретного запроса упало с 28 секунд до 142 миллисекунд, а итоговое время открытия отчёта снизилось с 30 секунд до 1,5 секунды; CPU базы опустился с 80% до 32%.

После починки производительности автор вынес бизнес-логику из Django view в Domain и Use Cases, чтобы тестировать сценарии без HTTP, базы и самого фреймворка. Сверху добавили mypy strict, Pytest с порогом покрытия 87% и блокирующий quality gate в GitLab CI: новые фичи стали выходить вдвое быстрее, а MTTD снизился на 40%.

Коротко

  • EXPLAIN ANALYZE показал полный Seq Scan по orders, 284100 строк мимо фильтра и время выполнения около 28 секунд для отчёта по филиалу.
  • После перехода на select_related и prefetch_related страница отчёта вместо 2800+ запросов к базе стала делать только 3 запроса.
  • Составной индекс по branch_id и created_at DESC и GIN-индекс для поиска по product name перевели запрос на Index Scan без полного сканирования.
  • Индекс создавали через CONCURRENTLY, чтобы не блокировать таблицу в продакшене и не получить простой на базе с сотнями тысяч записей.
  • Вынос логики в Domain и Use Cases, плюс Mypy, Pytest и quality gate в GitLab CI сократили TTM новых фич вдвое и снизили MTTD на 40%.

FAQ

Зачем в таком Django-монолите было не только ускорять SQL, но и отдельно выносить бизнес-логику из контроллеров в Domain и Use Cases?

Одной оптимизации запросов было мало: логика в контроллерах продолжала ломать старые части системы при каждом изменении. Вынос в Domain и Use Cases позволил тестировать сценарии отдельно от Django, базы и HTTP.

Почему автор сначала смотрел EXPLAIN ANALYZE, а уже потом правил ORM и добавлял индексы, вместо того чтобы просто индексировать таблицы наугад?

План запроса показал конкретные узкие места: полный скан, объём лишних строк и реальное время выполнения. После этого стало понятно, где проблема в N+1, а где нужен составной индекс.

Какой практический эффект дали quality gate, strict-типизация и тесты после рефакторинга, если основные проблемы вроде бы уже были сняты на уровне базы?

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

Читайте также

  1. SOLID в вашей дрели
  2. Я устал настраивать ПК и написал для Windows своё приложение на Flutter
  3. Как мы построили AI-экзоскелет для QA-инженера: от идеи до 11 автономных агентов
  4. Возвращаем к жизни связку OpenClaw и Claude
  5. Renga API: автоматизируем автоматизацию с помощью ИИ-агентов
Ключевые инсайты из новости (по версии ChatGPT)
  • EXPLAIN ANALYZE как первый шаг при жалобах на медленные отчёты: При разборе проблем с производительностью сначала нужно смотреть реальный план выполнения запроса, а не сразу добавлять индексы или переписывать код. EXPLAIN ANALYZE показывает, где именно возникает узкое место: полный скан таблицы, лишние строки после фильтрации, дорогие JOIN'ы или неудачный порядок операций.
    [Производительность БД]
Для получения полного доступа оформите подписку PubMag PRO.
Зарегистрированные пользователи видят только два тезиса.
Зарегистрироваться
Инсайты автоматически генерируются с помощью искусственного интеллекта на основе текста статьи.
← Назад в лентуЧитать оригинал →
✈️ Подписывайтесь на мой Telegram-канал — там еще больше интересного про AdTech, MarTech, AI и многое другое!