Дисклеймер: здесь и далее будем писать база данных (БД) имея ввиду система управления базами данных (СУБД)

В начале курса упоминули, что Django для работы с базой данных (БД) через ORM использует паттерн ActiveRecord. Это позволяет Django брать на себя задачи подключения к БД, составления и отправки запроса, преобразования ответа в удобный для работы из кода формат. В 98% случаев тебе не нужно думать как это работает, а в 2% случаев могут возникать ошибки.

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

Чаще твой код некорректно использует БД, чем сама БД "тормозит"

Посмотрим на типичные проблемы, с которыми сталкиваются:

  1. Кончились соединение с БД — когда приложение создает больше соединений, чем может обработать сервер БД
  2. Connection timeout (CONN_MAX) — когда соединения с базой данных "зависают" и не освобождаются
  3. N+1 запросы — когда Django запрашивает объекты по одному, вместо одного запроса
  4. Неоптимальные запросы — когда Django не может предсказать твою задачу и тащит слишком много данных

Сейчас рассмотрим подробнее сами проблемы, а как их решать — в следующей статье.

1. Кончились соединения с БД

Для работы с БД нужно установить соединение, послать последовательность запросов, авторизоваться, и только после этого можно делать "полезную" работу и работать с данными. Сама же БД должна провести множество внутренних работ по регистрации соединения. Иногда такие подготовительные работы могут занимать больше времени, чем сам запрос.

На типичной Django странице делается сразу несколько запросов:

  • Проверяем авторизацию пользователя (несколько запросов)
  • Отображаем профиль (один+ запрос)
  • Отображаем данные страницы (не менее одного запроса)

И получается, что для отрисовки 1 страницы может потребоваться сделать 5-10, а то и 100 запросов к БД.

Чтобы не тратить время на такую подготовку каждый раз, хорошо бы один раз установить соединение и его использовать для всех запросов. К тому же, у БД есть ограничение на количество соединений, например, у PostgreSQL по умолчанию 100. Поэтому принято перед БД и/или на уровне приложения создавать пул соединений, а также не сразу закрывать соединение, а чуть позже.

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

Как проявляется проблема

Получить доступ к полному материалу
Полный текст доступен в курсе