И двете проблемни стратегии за зареждане предизвикват изключения, ако се опитате да ги използвате с yield_per
, така че всъщност не е нужно да се тревожите твърде много.
Вярвам единственият проблем с subqueryload
е, че груповото зареждане на втората заявка не е реализирано (все още). Нищо няма да се обърка семантично, но ако използвате yield_per
, вероятно имате наистина добра причина да не искате да зареждате всички резултати наведнъж. Така че SQLAlchemy учтиво отказва да противоречи на вашите желания.
joinedload
е малко по-фин. Забранено е само в случай на колекция, където основният ред може да има множество асоциирани реда. Да кажем, че вашата заявка дава необработени резултати като този, където A и B са първични ключове от различни таблици:
A | B
---+---
1 | 1
1 | 2
1 | 3
1 | 4
2 | 5
2 | 6
Сега ги извличате с yield_per(3)
. Проблемът е, че SQLAlchemy може да ограничи само колко извлича по редове , но трябва да върне обекти . Тук SQLAlchemy вижда само първите три реда, така че създава A
обект с ключ 1 и три B
деца:1, 2 и 3.
Когато зареди следващата партида, иска да създаде нов A
обект с ключ 1... а, но той вече има един от тях, така че няма нужда да го създавате отново. Допълнителният B
, 4, се губи. (Така че, не, дори четене на присъединени колекции с yield_per
не е безопасно — парчета от вашите данни може да изчезнат.)
Може да кажете „е, просто продължете да четете редове, докато имате пълен обект“ – но какво ще стане, ако това A
има сто деца? Или милион? SQLAlchemy не може разумно да гарантира, че може да направи това, което поискате и дава правилни резултати, така че отказва да опита.
Не забравяйте, че DBAPI е проектиран така, че всякакъв базата данни може да се използва със същия API, дори ако тази база данни не поддържа всички функции на DBAPI. Имайте предвид, че DBAPI е проектиран около курсори, но MySQL всъщност не има курсори! Вместо това DBAPI адаптерите за MySQL трябва да ги фалшифицират.
Така че докато cursor.fetchmany(100)
ще работи , можете да видите от MySQLdbкод> изходен код
че не извлича мързеливо от сървъра; извлича всичко в един голям списък, след което връща парче, когато извикате fetchmany
.
Какво psycopg2
supports е истинско поточно предаване, при което резултатите се запомнят постоянно на сървъра и вашият Python процес вижда само няколко от тях наведнъж.
Все още можете да използвате yield_per
с MySQLdb
, или всеки друг DBAPI; това е целият смисъл на дизайна на DBAPI. Ще трябва да платите разходите за памет за всички сурови редове, скрити в DBAPI (които са кортежи, доста евтини), но няма също трябва да плащате за всички ORM обекти едновременно.