Какие есть стратегии загрузки данных
Что проверяют
У вопроса два прочтения, и хорошо, если вы это назовёте. Для бэкенда на Python чаще имеют в виду загрузку связанных объектов в ORM и проблему N+1, для задач с данными речь о полной, инкрементальной и потоковой загрузке. Следом просят показать, как вы находите N+1 в живом коде.
Как отвечать
В SQLAlchemy стратегия задаётся параметром lazy у relationship() или опцией запроса:
lazy="select": поведение по умолчанию. Связь грузится отдельным запросом при первом обращении к атрибуту. В цикле по сотне заказов это сто лишних запросов, то есть N+1;joinedload:LEFT OUTER JOINв том же запросе. Хорош для связей «многие к одному», на коллекциях размножает строки;selectinload: второй запрос видаWHERE id IN (...). Лучший выбор по умолчанию для коллекций «один ко многим»;raiseload: ленивая загрузка бросает исключение. Удобно в тестах: N+1 падает сразу, а не тормозит на проде;yield_per: большой результат отдаётся пачками, миллион объектов не лежит в памяти.
С AsyncSession это критично: неявная ленивая загрузка там падает с MissingGreenlet, связи нужно грузить явно.
В Django то же самое называется иначе: select_related делает JOIN для ForeignKey и OneToOneField, prefetch_related отдельным запросом тянет ManyToManyField и обратные связи, only() и defer() урезают колонки, iterator() не кеширует выборку.
Если речь о конвейере данных: полная перезаливка проста, но дорога; инкрементальная идёт по водяному знаку (updated_at, растущий id) или через CDC; потоковая читает события из очереди с минимальной задержкой.
Где спотыкаются
Ставят joinedload на все связи подряд. Две коллекции в одном JOIN дают декартово произведение, и запрос возвращает тысячи дублей.
Не могут показать N+1 на практике. Хватит echo=True в create_engine, django-debug-toolbar или счётчика запросов в тесте.
В инкрементальной загрузке берут водяной знак по времени без запаса. Строки, закоммиченные с опозданием, но с меньшим updated_at, теряются навсегда.