JavaRush /Курсы /Модуль 4: FastAPI /Тестирование и профилирование SQL-запросов в FastAPI и Dj...

Тестирование и профилирование SQL-запросов в FastAPI и Django

Модуль 4: FastAPI
11 уровень , 9 лекция
Открыта

Ваше приложение может быть безупречно реализовано, но если SQL-запросы медленные, пользователи быстро заметят это. Представьте себе, что ваш сервер — это шеф-повар, а ваш SQL-запрос — это заказ на приготовление еды. Если шеф долго ищет нужный ингредиент или готовит полчаса, клиенты начнут грустить (а потом писать плохие отзывы). Профилирование SQL-запросов помогает найти "узкие места" в производительности и оптимизировать их, а тестирование помогает убедиться, что всё работает правильно на разных сценариях использования.


Подходы к тестированию производительности запросов

Почему время выполнения запроса не всегда показатель? Дело в том, что скорость выполнения запросов отличается в зависимости от загруженности сервера, размера базы данных и даже используемой системы кэширования. Поэтому мы должны учитывать как абсолютное время (в миллисекундах), так и относительные характеристики, вроде количества операций чтения/записи.

Для тестирования запросов важно учитывать реальные сценарии использования. Например, если вы модель API для интернет-магазина, то запросы "получить топ-10 продуктов" или "найти продукт по SKU" будут выполняться чаще, чем, скажем, "удалить пользователя".

Чтобы быть уверенными в результатах, профиляция запросов проводится на реплике боевой базы или на данных, максимально приближённых к реальным.


Использование инструментов профилирования

SQLAlchemy позволяет включить логирование запросов через флаг echo=True. Это хорошая отправная точка, чтобы понять, какие запросы выполняются на самом деле.


from sqlalchemy import create_engine

DATABASE_URL = "postgresql+psycopg2://user:password@localhost/dbname"
engine = create_engine(DATABASE_URL, echo=True)  # Включаем логирование запросов

Теперь при каждом запросе вы увидите SQL-код в консоли. Например:


2023-01-01 12:00:00,123 INFO sqlalchemy.engine.Engine SELECT * FROM users WHERE id=1

Ну а в Django есть специальная библиотека — Django Debug Toolbar, которая помогает видеть, какие запросы выполняются и сколько времени они занимают.

Для начала установим её:


pip install django-debug-toolbar

Настроим INSTALLED_APPS и MIDDLEWARE в settings.py:


INSTALLED_APPS += ['debug_toolbar']

MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']

Добавим условие для отображения тулбара только на локальной машине:


INTERNAL_IPS = [
    "127.0.0.1",
]

Теперь вы сможете мониторить запросы через браузер. Например, для запроса вида:


users = User.objects.filter(is_active=True).select_related('profile')

Django Debug Toolbar покажет SQL-запрос и время его выполнения. Если там что-то начинает выглядеть подозрительно долго — у вас есть повод задуматься об оптимизации.

Профилирование в FastAPI с sqltap

Для профилирования запросов в FastAPI можно использовать библиотеку sqltap. Она позволяет собирать данные о выполненных запросах и их эффективности.

Установим sqltap:


pip install sqltap

Пример использования:


from fastapi import FastAPI
import sqlalchemy as sa
import sqltap

app = FastAPI()
DATABASE_URL = "sqlite:///./test.db"  # Для примера используем SQLite
engine = sa.create_engine(DATABASE_URL)

@app.middleware("http")
async def profile_sql(request, call_next):
    profiler = sqltap.start()
    response = await call_next(request)
    stats = profiler.stop()
    sqltap.report_text(stats, file=open("sql_report.txt", "w"))
    return response

После выполнения запросов вы получите отчёт sql_report.txt с информацией о времени выполнения каждого SQL-запроса.

Инструменты профилирования PostgreSQL

Если вы используете PostgreSQL, включение параметра EXPLAIN/EXPLAIN ANALYZE станет вашим лучшим другом. Эти команды показывают, как PostgreSQL исполняет запрос, сколько времени он занимает и какие индексы используются.

Пример:


EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';

Как интерпретировать результаты профилирования?

Ключевые показатели

  • Количество запросов: если для вывода одной страницы выполняется десяток запросов, это повод задуматься.
  • Задержка: запросы должны выполняться за миллисекунды. Если задержка измеряется в секундах, стоит оптимизировать логику.
  • Использование индексов: если запрос сканирует всю таблицу (Sequential Scan), проверьте правильность настроек индекса.

Антипаттерны

  1. N+1 проблема: выполняется много схожих запросов вместо одного. Например, загрузка списка пользователей с профилями:
    • Плохой запрос:
      
      users = User.query.all()
      for user in users:
          print(user.profile.name)  # Для каждого пользователя делается отдельный запрос!
                  
    • Хороший запрос:
      
      users = User.query.options(joinedload(User.profile)).all()
                  
  2. Нерациональное использование JOIN: слишком много связей в одном запросе может замедлить выполнение. Используйте select_related только там, где это необходимо.

Практические советы по улучшению производительности

1. Используйте select_related и prefetch_related в Django.

Эти методы помогают управлять связями и уменьшить количество запросов:


# Вместо обращения к базе для каждого поста делаем один запрос
posts = Post.objects.select_related('author').all()

2. Увеличивайте глубину выборки в SQLAlchemy через joinedload.

Если у вас есть таблицы с отношениями, избегайте дополнительных запросов:


from sqlalchemy.orm import joinedload

query = session.query(User).options(joinedload(User.profile))
users = query.all()

3. Ограничьте объём данных.

Запрашивайте только нужные поля:


# FastAPI: запрос только имени и email
users = session.query(User.name, User.email).all()

Как внедрить тестирование и профилирование в процесс разработки?

  1. Регулярно запускайте инструменты оптимизации во время разработки.
  2. Профилируйте запросы при добавлении новых функций.
  3. Автоматизируйте тестирование производительности, добавив тесты в CI/CD пайплайн. Например, можно сравнивать время выполнения запросов до и после изменений.
  4. Используйте инструменты мониторинга продакшн-базы, такие как New Relic, DataDog или Elastic APM.

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

1
Задача
Модуль 4: FastAPI, 11 уровень, 9 лекция
Недоступна
Профилирование запросов в FastAPI с sqltap
Профилирование запросов в FastAPI с sqltap
1
Задача
Модуль 4: FastAPI, 11 уровень, 9 лекция
Недоступна
Анализ N+1 проблемы
Анализ N+1 проблемы
3
Опрос
Управление индексами и ключами для повышения производительности, 11 уровень, 9 лекция
Недоступен
Управление индексами и ключами для повышения производительности
Управление индексами и ключами для повышения производительности
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Дмитрий/MrJonson Уровень 90
31 декабря 2025
Привет! Хочу обратить Ваше внимание на важный момент. В оригинальной статье упоминается библиотека sqltap, но есть проблема: Проблемы с sqltap: Последнее обновление: 2018 год Нет поддержки Python 3.8+ Не работает с асинхронными версиями SQLAlchemy Нет поддержки SQLAlchemy 1.4+ 🔧 Очень много материала в учебных статьях которые устарели и не используются уже давно Я понимаю знать может это и надо но тогда где свежий материал ?