Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+1 210новых вакансий за сутки·93 612вакансий открыто сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании7 266
РезюмеAIПодготовкаСтатьи
BoostТарифыBoost
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 401 кандидат открыт к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python17 126
  • Облачные технологии14 083
  • QA вакансии3 456
  • Backend вакансии2 116
  • Инженер данных1 809
  • Продакт-менеджер1 261

Разработка

  • Android1 862
  • iOS1 700
  • Fullstack вакансии990
  • AI вакансии951
  • Frontend вакансии749
  • Mobile вакансии44

По стеку

  • Go8 688
  • Java6 537
  • Node.js2 026
  • .NET1 722
  • Kotlin1 611
  • Rust1 458
  • C#710
  • PHP682
  • C++571

DevOps и инфраструктура

  • Kubernetes7 772
  • DevOps вакансии6 054
  • Linux-инфраструктура5 493
  • Terraform / IaC4 275
  • CI/CD3 239
  • Мониторинг и Observability1 790
  • SRE568
  • Кибербезопасность458

Аналитика и данные

  • Data Scientist1 143
  • Бизнес-аналитик923
  • Аналитик данных857
  • Системный аналитик152

Другие направления

  • Проджект-менеджер620
  • UI/UX дизайн147
  • Ручное тестирование14

По регионам

  • Вакансии в США44 437
  • Вакансии в Европе23 855
  • Вакансии в Канаде4 483
  • Работа в России3 904

По формату

  • Удалённые вакансии75 212
  • Релокация в США44 436
  • Гибридная работа12 388
  • Офисная работа7 083

По уровню

  • Senior вакансии42 625
  • Middle вакансии20 854
  • Junior вакансии6 721

Сейчас нанимают

Все компании
  • Wise190 вакансий
  • Rakuten189 вакансий
  • ASML166 вакансий
  • Grab137 вакансий
  • Celonis39 вакансий
  • Spotify37 вакансий
  • Adyen28 вакансий
  • Infobip28 вакансий
  • Monzo20 вакансий
  • Darktrace16 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме SQLAlchemyВсе вопросы
SQLAlchemySeniorКодинг

Как решить проблему N+1 запросов в SQLAlchemy с помощью selectinload или joinedload?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

selectinload делает отдельный SELECT IN для коллекций, joinedload добавляет JOIN для one-to-one/many-to-one. При async-сессии ленивая загрузка невозможна — всегда задавайте eager-опции явно.

Пример

from sqlalchemy import select
from sqlalchemy.orm import selectinload, joinedload
from sqlalchemy.ext.asyncio import AsyncSession

# selectinload: загружаем список заказов + их позиции
async def get_orders_with_items(session: AsyncSession):
    stmt = (
        select(Order)
        .options(selectinload(Order.items))   # отдельный SELECT IN
        .where(Order.status == "active")
    )
    result = await session.execute(stmt)
    return result.scalars().all()

# joinedload: загружаем заказы + автора (many-to-one)
async def get_orders_with_user(session: AsyncSession):
    stmt = (
        select(Order)
        .options(joinedload(Order.user))      # JOIN
        .where(Order.status == "active")
    )
    result = await session.execute(stmt)
    # scalars().unique() — важно при join, чтобы убрать дубли строк
    return result.scalars().unique().all()

# Вложенная загрузка: orders -> items -> product
async def get_deep(session: AsyncSession):
    stmt = (
        select(Order)
        .options(
            selectinload(Order.items)
            .joinedload(OrderItem.product)
        )
    )
    result = await session.execute(stmt)
    return result.scalars().all()

Проблема N+1 в SQLAlchemy

Проблема N+1 возникает, когда ORM сначала загружает список объектов (1 запрос), а затем для каждого объекта отдельно обращается к связанным данным (N запросов). При 1000 заказов это 1001 запрос вместо одного-двух.

Стратегии загрузки

SQLAlchemy 2.x предлагает несколько стратегий через функции-опции selectinload, joinedload, subqueryload и lazyload.

  • selectinload — выполняет отдельный SELECT … WHERE id IN (…) для коллекции. Не раздувает строки, безопасен для коллекций и many-to-many.
  • joinedload — добавляет LEFT OUTER JOIN к основному запросу. Хорош для загрузки единственного связанного объекта (many-to-one / one-to-one), но раздувает результат при коллекциях.
  • subqueryload — использует подзапрос; устарел, предпочитайте selectinload.
  • lazyload — поведение по умолчанию, отправляет запрос при первом обращении к атрибуту (источник N+1).

Диагностика N+1

Включите SQL-логирование и посчитайте запросы:

import logging
logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)

Или используйте sqlalchemy-utils / pytest-sqlalchemy-mock и считайте вызовы через event.listen на before_cursor_execute.

Когда что выбирать

  • Коллекция (one-to-many, many-to-many) → selectinload.
  • Единственный связанный объект (many-to-one) → joinedload.
  • Большой граф с несколькими уровнями → selectinload на каждом уровне отдельно, чтобы не перемножать строки.
  • Нужен только один столбец связанного объекта → contains_eager после явного join() или просто select() с нужными столбцами.

Подводные камни

  • joinedload на коллекциях дублирует строки родителя — без .unique() получите повторы объектов в списке.
  • lazy="raise" в production — полезная защита, но сломает код, если забыть добавить опцию загрузки хоть для одного маршрута.
  • selectinload с очень большим IN-списком (10 000+ id) может замедлить PostgreSQL из-за переполнения плана; разбивайте батчами или переходите на subqueryload.
  • AsyncSession + lazyload бросает MissingGreenlet — в async-коде ленивая загрузка физически невозможна без AsyncAttrs или явного eager-options.
  • contains_eager без явного join не работает — ORM не знает, что данные уже есть в строке результата.
  • Вложенный selectinload × joinedload: порядок имеет значение — joinedload внутри selectinload работает, обратное может дать неожиданный SQL.
  • expire_on_commit=True (по умолчанию): после коммита все атрибуты помечаются устаревшими, и следующее обращение снова вызовет SELECT — даже если вы уже загрузили данные через eager.
  • Профилирование только в dev: убедитесь, что echo=True отключён в prod, иначе логирование каждого SQL-запроса само станет узким местом.

Типичные ошибки

  • Описывать n plus one loading только как термин и не показывать механизм на минимальном примере.
  • Игнорировать ошибки, пустые данные, конкурентный доступ или границы транзакции.
  • Не связывать поведение с официальным контрактом SQLAlchemy и реальной эксплуатацией.

Что проверяет интервьюер

  • Объясняет n plus one loading через последовательность действий, а не через набор ключевых слов.
  • Приводит короткий кодовый пример или production-сценарий с ожидаемым поведением.
  • Называет хотя бы один риск: производительность, безопасность, транзакции, память или сопровождение.
  • Умеет обсудить отказ, наблюдаемость и rollback без изменения публичного контракта.

Как вы знаете этот вопрос?

Проверить себя по теме SQLAlchemy →

Источники

  • https://docs.sqlalchemy.org/en/20/orm/queryguide/relationships.html
  • https://docs.sqlalchemy.org/en/20/orm/basic_relationships.html
Следующий вопрос→Как работает `Session` в SQLAlchemy и что такое паттерн Unit of Work?

Связанные темы

SQLAlchemydatabase-designimplementationtechnical-reasoning

Вакансии с этим навыком

  • Python developer

Частые вопросы на собеседовании

  • Как работает Session в SQLAlchemy и что такое паттерн Unit of Work?
  • Как делать zero-downtime миграции с Alembic и SQLAlchemy models?
  • Что такое Engine в SQLAlchemy и как работает пул соединений?
  • В чём разница между стратегиями загрузки lazy='select', lazy='joined' и lazy='selectin'?