Большинство реализаций DBAPI полностью буферизуют строки по мере их извлечения - поэтому обычно, прежде чем SQLAlchemy ORM даже получит один результат, весь набор результатов находится в памяти.
Но тогда способ Query
работы таков, что он полностью загружает данный набор результатов по умолчанию перед возвратом вам ваших объектов. Обоснование здесь касается запросов, которые представляют собой нечто большее, чем простые операторы SELECT. Например, в соединениях с другими таблицами, которые могут возвращать один и тот же идентификатор объекта несколько раз в одном наборе результатов (обычно при активной загрузке), полный набор строк должен находиться в памяти, чтобы можно было возвращать правильные результаты, в противном случае коллекции и т. может быть заселен только частично.
Так что Query
предлагает возможность изменить это поведение через yield_per()
. Этот вызов приведет к тому, что объект будет Query
выдавать строки в пакетах, в которых вы указываете размер пакета. Как указано в документации, это уместно только в том случае, если вы не выполняете какую-либо активную загрузку коллекций, так что в основном, если вы действительно знаете, что делаете. Кроме того, если нижележащий DBAPI предварительно буферизует строки, эти накладные расходы на память все равно будут, поэтому подход масштабируется лишь немного лучше, чем его не использовать.
Я почти никогда не использую yield_per()
; вместо этого я использую лучшую версию подхода LIMIT, который вы предлагаете выше, с использованием оконных функций. LIMIT и OFFSET имеют огромную проблему, заключающуюся в том, что очень большие значения OFFSET заставляют запрос становиться все медленнее и медленнее, поскольку OFFSET N заставляет его пролистывать N строк - это все равно, что выполнять один и тот же запрос пятьдесят раз вместо одного, каждый раз читая все большее и большее количество рядов. Используя подход с оконной функцией, я предварительно выбираю набор «оконных» значений, которые относятся к фрагментам таблицы, которые я хочу выбрать. Затем я испускаю отдельные операторы SELECT, которые каждый раз извлекают из одного из этих окон.
Подход с оконными функциями есть в вики, и я использую его с большим успехом.
Также обратите внимание: не все базы данных поддерживают оконные функции; вам нужен Postgresql, Oracle или SQL Server. ИМХО, использование хотя бы Postgresql того стоит - если вы используете реляционную базу данных, вы можете использовать лучшее.