Чтобы привести документацию SQLalchemy:
Метод Query.yield_per() несовместим с большинством активных схем загрузки, включая subqueryload и joinload с коллекциями.
Предупреждение
Используйте этот метод с осторожностью; если один и тот же экземпляр присутствует в нескольких партиях строк, изменения в атрибутах конечного пользователя будут перезаписаны.
В частности, обычно невозможно использовать этот параметр с загруженными коллекциями (т.е. любой lazy = join или 'subquery), поскольку эти коллекции будут очищены для новой загрузки, если они встречаются в последующей партии результатов. В случае "загрузки подзапроса" получается полный результат для всех строк, который обычно побеждает цель yield_per().
Также обратите внимание, что хотя yield_per() установит параметр исполнения stream_results в значение True, в настоящее время это понимается только на диалекте psycopg2, который будет передавать результаты с использованием курсоров на стороне сервера вместо предварительного буфера всех строк для этого запроса. Другие DBAPI предварительно загружают все строки, прежде чем сделать их доступными. Использование необработанных строк базы данных в памяти намного меньше, чем использование объекта с отображением ORM, но его следует учитывать при бенчмаркинге.
У меня действительно есть проблема с пониманием того, как работает yield_per()
и в чем проблема с использованием этого метода. Также верный способ обхода этих проблем и продолжать использовать эту функцию для итерации над огромным количеством строк.
Меня интересует вся необходимая конструктивная информация, но здесь есть некоторые подсказки:
- Как может быть несколько экземпляров одной и той же строки? Только через отношения (если две строки итерационной таблицы имеют FK в той же строке в другой таблице)? Есть ли проблема, если вы не знаете, что это происходит, или вы только читаете атрибуты отношений?
- lazy = join или 'subquery не возможны, но почему именно? Оба они являются частью вашего запроса, на который вы вызываете
yield_per()
.- Если они очищаются в последующей партии результатов, просто загрузите ее снова. Так где же проблема? Или это единственная проблема, из-за которой вы теряете изменения в ваших отношениях, если они вносили изменения?
- В случае загрузки подзапроса, почему все строки выбраны? SQL Server, возможно, придется сохранить большую таблицу, но почему бы просто не возвратить результат пакетами один за другим для всего запроса?
- В примере в
yield_per()
docq = sess.query(Object).yield_per(100).options(lazyload('*'), joinedload(Object.some_related))
они деактивируют eagerload с помощьюlazyload('*')
, но сохраняют единую объединенную нагрузку. Есть ли способ использоватьyield_per()
с eagerload? Каковы условия?
- Говорят, что
psycopg2
- это единственный DBAPI, который поддерживает поток потока. Итак, это единственный DBAPI, который вы можете использовать сyield_per()
? Насколько я понимаю,yield_per
использует функциюcursor.fetchmany()
() функции DBAPI, которая поддерживает многие из них. И насколько я понимаю,cursor.fetchmany()
поддерживает выборку только частей результата и не извлекает все (если он будет извлекать все, почему функция существует?) - У меня такое ощущение, что
yield_per()
полностью безопасен (даже с eagerload), если вы только читаете доступ (например, для статистики). Это правильно?