Этот вопрос проверяет понимание того, почему «загрузить всё в память» — плохая идея и к каким сбоям это приводит.
Если загрузить слишком много строк в память, приложение может начать тормозить или упасть по Out Of Memory. Даже если памяти хватает, сборщик мусора и обработка больших списков могут сильно замедлить работу. В ORM-сценариях объекты дополнительно кешируются в сессии, и память растет быстрее, чем ожидаешь. Также увеличивается время ответа и нагрузка на сеть между приложением и базой.
Когда ты делаешь что-то вроде .all() на огромном запросе, ты платишь сразу в нескольких местах: память, CPU, GC, сеть и даже сама БД.
OOM (Out Of Memory) — состояние, когда приложению не хватает оперативной памяти, из-за чего процесс может быть завершен или начать аварийно работать.
Проблемы:
Пик памяти растет пропорционально числу строк и размеру данных.
В контейнерах (Docker/Kubernetes) процесс могут убить по лимиту памяти.
Пример анти-паттерна:
users = session.execute(select(User)).scalars().all() # может быть миллионы строк
Даже если памяти хватает:
Большие списки и множество объектов вызывают частые паузы на сборку мусора.
Python начинает тратить время на управление памятью, а не на полезную работу.
Если ты читаешь ORM-объекты, сессия часто хранит ссылки на них.
Это удобно для согласованности, но вредно для bulk-чтения.
Что делать:
Читать нужные колонки вместо целых объектов.
Обрабатывать порциями и очищать сессию.
Большой ответ дольше передается по сети.
Дольше сериализуется (если это API).
Дольше держит соединение с БД занятым.
Читать потоково/порциями.
Выбирать только нужные поля.
Использовать keyset pagination для больших таблиц.
Не делать .all() без уверенности, что данных мало.
Загружать много строк в память стоит только когда данные гарантированно небольшие. Во всех остальных случаях безопаснее и быстрее работать порциями или потоково, особенно при использовании ORM.