Короткий ответ
'select' (по умолчанию) делает отдельный запрос на каждый доступ к связи; 'joined' добавляет LEFT OUTER JOIN в основной запрос; 'subquery' выполняет отдельный подзапрос для всех связанных объектов сразу; 'selectin' выполняет отдельный SELECT ... WHERE id IN (...) для всех родительских id сразу — обычно это предпочтительный вариант для коллекций.
Как это работает подробнее
'joined' увеличивает размер результата основного запроса (дублирование строк родителя при JOIN к коллекции); 'subquery' и 'selectin' выполняют единственный дополнительный запрос для всех объектов партии, но 'selectin' эффективнее за счёт простого IN-списка и лучше работает с LIMIT/OFFSET.
Пример кода
example.py
from sqlalchemy.orm import selectinload
stmt = select(Author).options(selectinload(Author.books))
authors = session.scalars(stmt).all()
for author in authors:
print(author.name, len(author.books))
# SQLAlchemy выполнит ровно 2 запроса: один по authors, один SELECT id, title, author_id FROM books WHERE author_id IN (1, 2) по booksЧто использовать на практике
- Практика. 'joined' хорошо подходит для связей «один-к-одному»/«многие-к-одному» с небольшим числом строк; 'selectin' — предпочтительный выбор для коллекций в современных версиях SQLAlchemy, переопределяется через options(selectinload(...)).
Подводные камни
- Ошибка. Используют 'joined' для коллекций с большим количеством связанных строк, получая умножение строк результата; не указывают стратегию загрузки вовсе, получая N+1 при итерации по объектам в цикле.