DEV Community

Гимаев Наиль
Гимаев Наиль

Posted on

Отладчик Pycharm против проблемы 1+N

Лирика

К примеру, требуется вывести в API список пользователей, но не все данные, а только их username, и поэтому queryset=User.objects.only('username'). Допустим, что за один запрос выводится список из 20 пользователей. Теперь мы решили добавить поля first_name и last_name (в сериализатор, но не в queryset). Django Rest Framework перебирает все объекты по очереди. Не обнаружив в текущем объекте поля first_name, django делает запрос в БД за данными этого поля, потом повторяет то же самое для last_name. И так для каждого объекта. В результате имеем один запрос к БД для получения списка объектов и ещё 20 раз по 2 запроса. Итого 41 запрос.
В данном случае достаточно добавить недостающие поля в only или не использовать метод only вовсе. Даже тот, кто знает о коварстве метода only, может не знать об его участии в данном фрагменте кода. А всё потому, что подготовка queryset происходит во view, а использование в serializator.
Описанный случай, является достаточно экзотичным, но хорошо показывает, как на пустом месте вместо одного запроса можно получить множество. Гораздо чаще приходится прописывать prefetch_related для борьбы с 1+N.

Задействуем мощь отладчика Pycharm

Если при ручном тестировании своего кода мне нужно делать обращение к API, то я всегда включаю вывод логов отладчика, чтобы видеть обращение к БД. Я покажу как это делается, но перед этим вам нужно прочитать


Прочитали? Тогда начинаем.
  1. Откройте свой проект django и перейдите по ссылке CursorDebugWrapper.execute или CursorDebugWrapper.debug_sql если у вас Django 3+
  2. Поставьте breakpoint на logger.debug
  3. Сделайте правый клик на красном кружке
  4. В появившимся диалоге отключите Suspend
  5. Включите Evalute and log и напишите '(%.3f) %s; args=%s'%(duration, sql, params)

Должно получится так:

Screenshot of Pycharm

Теперь, если вы запустите проект под отладчиком, то увидите в консоли все запросы к БД и время их выполнения. В моём проекте запросов в БД от вызова одного API не очень много и 1+N сразу бросается в глаза, если не включен cacheops. Отключайте cacheops на машине разработки, тогда неправильные запросы к БД вы будете буквально чувствовать на собственной шкуре без всякого логирования и не допустите плохой код в проект.
Главная прелесть логирования через отладчик в том, что не требуется вносить изменения в код, и не придётся убирать за собой забытые print'ы. При этом я не удаляю breakpoint, когда он мне не нужен, а просто выключаю (Ctrl+Shift+F8). А когда становится нужен, снова включаю. Т.е. настроив breakpoint один раз, пользуюсь им всё время.

Но нужно знать 2 вещи. Во-первых, без отладчика эта история не работает. Во-вторых, даже с отладчиком эта история не работает, если у вас mssql aka SQL Server.

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

Top comments (0)