sql >> Database >  >> RDS >> Mysql

De `yield_per()`-problemen van SQLalchemy beter begrijpen

Beide problematische laadstrategieën veroorzaken uitzonderingen als je ze probeert te gebruiken met yield_per , zodat u zich niet al te veel zorgen hoeft te maken.

Ik geloof het enige probleem met subqueryload is dat batchgewijs laden van de tweede query (nog) niet is geïmplementeerd. Semantisch zou er niets mis gaan, maar als je yield_per . gebruikt , heb je waarschijnlijk een hele goede reden om niet alle resultaten in één keer te willen laden. Dus SQLAlchemy weigert beleefd tegen uw wensen in te gaan.

joinedload is wat subtieler. Het is alleen verboden in het geval van een verzameling, waarbij een primaire rij meerdere gekoppelde rijen kan hebben. Stel dat uw zoekopdracht onbewerkte resultaten zoals deze oplevert, waarbij A en B primaire sleutels zijn uit verschillende tabellen:

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

Nu haal je deze op met yield_per(3) . Het probleem is dat SQLAlchemy alleen kan beperken hoeveel het ophaalt met rijen , maar het moet objecten teruggeven . Hier ziet SQLAlchemy alleen de eerste drie rijen, dus het creëert een A object met toets 1 en drie B kinderen:1, 2 en 3.

Wanneer het de volgende batch laadt, wil het een nieuwe A . maken object met sleutel 1... ah, maar het heeft er al een, dus het is niet nodig om het opnieuw te maken. De extra B , 4, is verloren. (Dus nee, zelfs het lezen van samengevoegde collecties met yield_per is onveilig — stukjes van uw gegevens kunnen verloren gaan.)

Je zou kunnen zeggen "nou, blijf gewoon rijen lezen totdat je een volledig object hebt" - maar wat als die A heeft honderd kinderen? Of een miljoen? SQLAlchemy kan redelijkerwijs niet garanderen dat het kan doen wat je hebt gevraagd en juiste resultaten produceren, dus weigert het het te proberen.

Onthoud dat de DBAPI zo is ontworpen dat elke database kan worden gebruikt met dezelfde API, zelfs als die database niet alle DBAPI-functies ondersteunt. Bedenk dat de DBAPI is ontworpen rond cursors, maar dat MySQL niet echt heeft cursors! De DBAPI-adapters voor MySQL moeten ze in plaats daarvan vervalsen.

Dus terwijl cursor.fetchmany(100) zal werken , kunt u zien van de MySQLdb broncode dat het niet lui van de server haalt; het haalt alles op in één grote lijst en retourneert vervolgens een segment wanneer je fetchmany aanroept .

Wat psycopg2 ondersteunt is echte streaming, waarbij de resultaten persistent worden onthouden op de server, en je Python-proces ziet er maar een paar tegelijk.

Je kunt nog steeds yield_per . gebruiken met MySQLdb , of een andere DBAPI; dat is het hele punt van het ontwerp van de DBAPI. U moet de geheugenkosten betalen voor alle onbewerkte rijen die verborgen zijn in de DBAPI (dit zijn tupels, redelijk goedkoop), maar u zult ook moet tegelijkertijd voor alle ORM-objecten betalen.



  1. SQLite of MySql? Hoe beslissen?

  2. Android-toegang tot externe SQL-database

  3. Bewaar en herhaal het resultaat van de zoekopdracht in mysqli

  4. Sluiten is nooit expliciet aangeroepen op Database