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

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

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

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

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

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

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

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

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

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

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

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

Все подборки
  • Python17 129
  • Облачные технологии14 088
  • QA вакансии3 457
  • Backend вакансии2 115
  • Инженер данных1 805
  • Продакт-менеджер1 262

Разработка

  • Android1 865
  • iOS1 698
  • Fullstack вакансии989
  • AI вакансии949
  • Frontend вакансии744
  • Mobile вакансии44

По стеку

  • Go8 660
  • Java6 550
  • Node.js2 020
  • .NET1 722
  • Kotlin1 619
  • Rust1 455
  • C#711
  • PHP683
  • C++572

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

  • Kubernetes7 769
  • DevOps вакансии6 056
  • Linux-инфраструктура5 493
  • Terraform / IaC4 266
  • CI/CD3 250
  • Мониторинг и Observability1 788
  • SRE567
  • Кибербезопасность453

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

  • Data Scientist1 141
  • Бизнес-аналитик927
  • Аналитик данных854
  • Системный аналитик153

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

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

По регионам

  • Вакансии в США44 281
  • Вакансии в Европе23 875
  • Вакансии в Канаде4 475
  • Работа в России3 922

По формату

  • Удалённые вакансии75 035
  • Релокация в США44 281
  • Гибридная работа12 401
  • Офисная работа7 079

По уровню

  • Senior вакансии42 679
  • Middle вакансии20 894
  • Junior вакансии6 722

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

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

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

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

В чём разница между стратегиями загрузки lazy='select', lazy='joined' и lazy='selectin'?

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

lazy='select' — отдельный SELECT при обращении к атрибуту (N+1, не работает в async); lazy='joined' — один JOIN-запрос (рискует декартовым произведением для коллекций); lazy='selectin' — два запроса с IN-условием, рекомендован для async и больших коллекций.

lazy='select' (по умолчанию)

При обращении к атрибуту впервые выполняется отдельный SELECT. Это классический «ленивый» режим.

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    orders: Mapped[list["Order"]] = relationship(lazy="select")  # default

class Order(Base):
    __tablename__ = "orders"
    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column()

# Синхронный код — работает:
with Session(engine) as session:
    users = session.execute(select(User)).scalars().all()
    for user in users:
        print(user.orders)  # N дополнительных SELECT-ов — N+1 проблема!

# В async-сессии lazy='select' ЗАПРЕЩЁН:
async with AsyncSession(engine) as session:
    users = (await session.execute(select(User))).scalars().all()
    # Следующая строка вызовет MissingGreenlet или greenlet_spawn error:
    # print(users[0].orders)  # ОШИБКА!

Lazy select — источник N+1 проблем. Для async ORM он фактически неприменим без явного eager-загрузчика.

Стратегии загрузки связанных объектов в SQLAlchemy

SQLAlchemy предоставляет несколько стратегий загрузки для relationship-атрибутов. Выбор стратегии напрямую влияет на количество SQL-запросов и производительность приложения. Ниже разобраны три ключевых варианта.

lazy='joined' / joinedload

Выполняет LEFT OUTER JOIN к основному запросу. Все данные приходят в одном SQL-запросе.

from sqlalchemy.orm import joinedload

async with AsyncSession(engine) as session:
    stmt = (
        select(User)
        .options(joinedload(User.orders))
        .where(User.id == 1)
    )
    result = await session.execute(stmt)
    # unique() обязателен при joinedload с коллекциями — дедупликация строк после JOIN
    user = result.unique().scalar_one()
    print(user.orders)  # уже загружены, без дополнительных запросов

Плюс: 1 запрос. Минус: при больших коллекциях JOIN возвращает декартово произведение — если у 100 пользователей по 50 заказов, вернётся 5000 строк. Лучше для связей «один к одному» или небольших коллекций.

lazy='selectin' / selectinload

Выполняет два SELECT: первый загружает родительские объекты, второй — все дочерние объекты с WHERE parent_id IN (...).

from sqlalchemy.orm import selectinload

async with AsyncSession(engine) as session:
    stmt = (
        select(User)
        .options(selectinload(User.orders))
    )
    result = await session.execute(stmt)
    users = result.scalars().all()
    # 2 запроса суммарно, независимо от числа пользователей
    for user in users:
        print(user.orders)  # загружены без N+1

Оптимален для коллекций с умеренным числом элементов. Не раздувает результирующий набор, как JOIN.

Сравнительная таблица

  • lazy='select': N+1 запросов, не работает в async без явного eager, хорош только для случаев, когда коллекция нужна редко.
  • lazy='joined' / joinedload: 1 запрос с JOIN, риск декартова произведения при больших коллекциях, хорош для one-to-one и небольших many-to-one.
  • lazy='selectin' / selectinload: 2 запроса с IN-условием, безопасен для больших коллекций, рекомендован для async ORM.

Вложенная загрузка

from sqlalchemy.orm import selectinload, joinedload

# User -> orders -> items
stmt = (
    select(User)
    .options(
        selectinload(User.orders).selectinload(Order.items)
    )
)

# Смешанная: joinedload для ManyToOne, selectinload для коллекций
stmt = (
    select(Order)
    .options(
        joinedload(Order.user),        # один пользователь — JOIN OK
        selectinload(Order.items),     # коллекция — selectin лучше
    )
)

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

  • MissingGreenlet в async: lazy='select' в asyncio вызывает sqlalchemy.exc.MissingGreenlet при попытке обратиться к незагруженному атрибуту. Всегда указывайте eager-загрузчик явно.
  • unique() после joinedload: result.scalars().all() после joinedload с коллекцией возвращает дубликаты. Нужно result.unique().scalars().all().
  • Декартово произведение: joinedload по нескольким коллекциям одновременно (orders и tags) создаёт произведение строк. Используйте selectinload для второй коллекции.
  • IN-список при selectin: при очень большом числе родительских объектов (>10 000) IN-запрос может стать медленным — проверяйте план запроса.
  • lazy на уровне модели vs опция запроса: настройка lazy= в relationship определяет поведение по умолчанию, но .options(selectinload(...)) перекрывает её для конкретного запроса. Предпочитайте явные опции запроса.
  • raiseload для безопасности: используйте lazy='raise' или raiseload('*') чтобы явно запретить ленивую загрузку и поймать N+1 на стадии разработки.
  • subqueryload устарел: в SQLAlchemy 2.0 subqueryload менее производителен, чем selectinload — не используйте его в новом коде.

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

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

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

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

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

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

Источники

  • https://docs.sqlalchemy.org/en/20/orm/queryguide/relationships.html
  • https://docs.sqlalchemy.org/en/20/orm/basic_relationships.html
←Предыдущий вопросЧто такое `Engine` в SQLAlchemy и как работает пул соединений?Следующий вопрос→Как сравнить SQLAlchemy с raw SQL, query builder и другими ORM по контролю, типобезопасности и производительности?

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

SQLAlchemydatabase-designtechnical-reasoning

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

  • Python developer

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

  • Как решить проблему N+1 запросов в SQLAlchemy с помощью selectinload или joinedload?
  • Как работает Session в SQLAlchemy и что такое паттерн Unit of Work?
  • Как делать zero-downtime миграции с Alembic и SQLAlchemy models?
  • Что такое Engine в SQLAlchemy и как работает пул соединений?