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

Тестування та профілювання 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.

Ці методи допоможуть вам не тільки знайти слабкі місця в застосунку, але й навчитися грамотно вирішувати проблеми, пов'язані з продуктивністю. У наступній лекції ми розберемо... що ж, читайте і дізнаєтесь!

3
Опитування
Управління індексами та ключами для підвищення продуктивності, рівень 11, лекція 9
Недоступний
Управління індексами та ключами для підвищення продуктивності
Управління індексами та ключами для підвищення продуктивності
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ