> Как оптимизировать SQL запросы (Python)

Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы

Компании: ProFinansy, IPChain

Стек: Python

> Пример ответа

Оптимизация SQL-запросов в Python-бэкенде начинается с анализа узких мест. Первым делом используйте EXPLAIN ANALYZE в PostgreSQL или EXPLAIN QUERY PLAN в SQLite, чтобы увидеть, как база данных выполняет запрос. Ищите последовательные сканирования (Seq Scan) вместо индексных (Index Scan) - это главный признак проблемы.

Основные техники:

  1. Индексы: Создавайте индексы на столбцы, используемые в WHERE, JOIN, ORDER BY. Для поиска по тексту используйте GIN-индексы. Избегайте избыточных индексов - они замедляют запись.
  2. Избегайте N+1 запросов: В ORM (например, SQLAlchemy) используйте joinedload() или selectinload() для подгрузки связанных данных. Пример:
    PYTHON
    # Плохо: N+1
    users = session.query(User).all()
    for user in users:
    print(user.addresses)
    # Хорошо: один запрос с JOIN
    users = session.query(User).options(joinedload(User.addresses)).all()
  3. Выбирайте только нужные столбцы: Вместо SELECT * указывайте конкретные поля. Это уменьшает передаваемый объём данных.
  4. Используйте пакетные операции: Для массовой вставки применяйте bulk_insert_mappings() в SQLAlchemy, а не цикл с отдельными INSERT.
  5. Оптимизируйте JOIN'ы: Убедитесь, что поля соединения проиндексированы. Для больших таблиц рассмотрите денормализацию или материализованные представления.
  6. Лимитируйте результаты: Всегда добавляйте LIMIT и OFFSET (или курсоры) для пагинации, чтобы не загружать миллионы строк.
  7. Кеширование: Для часто запрашиваемых, редко меняющихся данных используйте Redis или кеш на уровне приложения (например, functools.lru_cache).

Пример оптимизации: если запрос фильтрует по created_at, добавьте индекс:

SQL
CREATE INDEX idx_orders_created_at ON orders(created_at);

И в коде:

PYTHON
# Вместо фильтрации в Python
orders = [o for o in session.query(Order).all() if o.created_at > date]
# Делайте фильтрацию в SQL
orders = session.query(Order).filter(Order.created_at > date).all()

Используйте профилировщики (например, cProfile или py-spy), чтобы найти медленные участки, и всегда тестируйте изменения на репрезентативных данных.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью