sql >> Database teknologi >  >> RDS >> Mysql

Forstå SQLalchemys `yield_per()`-problemer bedre

Begge de problematiske indlæsningsstrategier giver undtagelser, hvis du forsøger at bruge dem med yield_per , så du behøver egentlig ikke bekymre dig for meget.

Jeg tror det eneste problem med subqueryload er, at batch-indlæsning af den anden forespørgsel ikke er implementeret (endnu). Intet ville gå semantisk galt, men hvis du bruger yield_per , har du sikkert en rigtig god grund til ikke at ville indlæse alle resultaterne på én gang. Så SQLAlchemy nægter høfligt at gå imod dine ønsker.

joinedload er lidt mere subtil. Det er kun forbudt i tilfælde af en samling, hvor en primær række kan have flere tilknyttede rækker. Lad os sige, at din forespørgsel producerer rå resultater som dette, hvor A og B er primærnøgler fra forskellige tabeller:

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

Nu henter du disse med yield_per(3) . Problemet er, at SQLAlchemy kun kan begrænse, hvor meget den henter efter rækker , men den skal returnere objekter . Her ser SQLAlchemy kun de første tre rækker, så det opretter en A objekt med tast 1 og tre B børn:1, 2 og 3.

Når den indlæser den næste batch, vil den oprette en ny A objekt med tast 1... ah, men det har allerede en af ​​dem, så det er ikke nødvendigt at oprette det igen. Den ekstra B , 4, er tabt. (Så nej, selv at læse samlede samlinger med yield_per er usikker — bidder af dine data kan forsvinde.)

Du siger måske "godt, bare fortsæt med at læse rækker, indtil du har et fuldt objekt" - men hvad nu hvis det A har hundrede børn? Eller en million? SQLAlchemy kan ikke med rimelighed garantere, at det kan gøre, hvad du bad om og producere korrekte resultater, så den nægter at prøve.

Husk, at DBAPI er designet, så enhver databasen kan bruges med den samme API, selvom databasen ikke understøtter alle DBAPI-funktionerne. Overvej, at DBAPI er designet omkring markører, men MySQL har faktisk ikke har markører! DBAPI-adapterne til MySQL skal i stedet forfalske dem.

Så mens cursor.fetchmany(100) vil arbejde , kan du se fra MySQLdb kildekode at det ikke henter dovent fra serveren; den henter alt til én stor liste og returnerer derefter et udsnit, når du kalder fetchmany .

Hvad psycopg2 understøtter er ægte streaming, hvor resultaterne huskes vedvarende på serveren, og din Python-proces ser kun nogle få af dem ad gangen.

Du kan stadig bruge yield_per med MySQLdb , eller enhver anden DBAPI; det er hele pointen med DBAPI's design. Du skal betale hukommelsesomkostningerne for alle de rå rækker, der er gemt væk i DBAPI'en (som er tupler, ret billige), men du vil ikke også skal betale for alle ORM-objekterne på samme tid.



  1. Optimizer-begrænsninger med filtrerede indekser

  2. Doktrin 2 kortlægning, der henviser til unik nøgle

  3. Hvad er den mest effektive måde at gemme en sorteringsrækkefølge på en gruppe af poster i en database?

  4. Venstre JOIN hurtigere eller indre Join hurtigere?