sql >> Databasteknik >  >> RDS >> Mysql

Bättre förstå SQLalchemys `yield_per()`-problem

Båda de problematiska laddningsstrategierna ger undantag om du försöker använda dem med yield_per , så du behöver egentligen inte oroa dig för mycket.

Jag tror det enda problemet med subqueryload är att batchladdning av den andra frågan inte är implementerad (ännu). Inget skulle gå fel semantiskt, men om du använder yield_per , du har förmodligen en riktigt bra anledning att inte vilja ladda alla resultat på en gång. Så SQLAlchemy vägrar artigt att gå emot dina önskemål.

joinedload är lite mer subtil. Det är bara förbjudet i fallet med en samling, där en primär rad kan ha flera associerade rader. Säg att din fråga ger råresultat som detta, där A och B är primärnycklar från olika tabeller:

 A | B 
---+---
 1 | 1 
 1 | 2 
 1 | 3 
 1 | 4 
 2 | 5 
 2 | 6 

Nu hämtar du dessa med yield_per(3) . Problemet är att SQLAlchemy bara kan begränsa hur mycket den hämtas av rader , men den måste returnera objekt . Här ser SQLAlchemy bara de tre första raderna, så det skapar en A objekt med tangent 1 och tre B barn:1, 2 och 3.

När den laddar nästa batch vill den skapa en ny A objekt med nyckel 1... ah, men det har redan en av dessa, så du behöver inte skapa det igen. Den extra B , 4, är förlorad. (Så nej, även att läsa sammanfogade samlingar med yield_per är osäker — delar av din data kan försvinna.)

Du kanske säger "ja, fortsätt bara att läsa rader tills du har ett helt objekt" - men tänk om det A har hundra barn? Eller en miljon? SQLAlchemy kan inte rimligen garantera att den kan göra vad du bad om och ger korrekta resultat, så den vägrar att försöka.

Kom ihåg att DBAPI är utformad så att alla databasen kan användas med samma API, även om den databasen inte stöder alla DBAPI-funktioner. Tänk på att DBAPI är designad kring markörer, men att MySQL faktiskt inte har markörer! DBAPI-adaptrarna för MySQL måste förfalska dem istället.

Så medan cursor.fetchmany(100) kommer att fungera , kan du se från MySQLdb källkod att det inte hämtas lätt från servern; den hämtar allt till en stor lista och returnerar sedan en del när du anropar fetchmany .

Vad psycopg2 supports är sann streaming, där resultaten kommer ihåg ständigt på servern, och din Python-process ser bara ett fåtal av dem åt gången.

Du kan fortfarande använda yield_per med MySQLdb , eller någon annan DBAPI; det är hela poängen med DBAPI:s design. Du måste betala minneskostnaden för alla rårader som är gömda i DBAPI (som är tuplar, ganska billigt), men du kommer inte också måste betala för alla ORM-objekt samtidigt.



  1. Hur man visar sammanställningen av en databas i MySQL

  2. Undviker kapslade frågor

  3. MariaDB CONNECTION_ID() förklaras

  4. Hur återskapar man en raderad tabell med Django Migrations?