Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Verstehen Sie die `yield_per()`-Probleme von SQLalchemy besser

Beide problematischen Ladestrategien lösen Ausnahmen aus, wenn Sie versuchen, sie mit yield_per zu verwenden , also brauchen Sie sich nicht allzu viele Sorgen zu machen.

Ich glaube das einzige Problem mit subqueryload ist, dass das Stapelladen der zweiten Abfrage (noch) nicht implementiert ist. Semantisch würde nichts schief gehen, aber wenn Sie yield_per verwenden , haben Sie wahrscheinlich einen wirklich guten Grund, nicht alle Ergebnisse auf einmal laden zu wollen. Daher weigert sich SQLAlchemy höflich, gegen Ihre Wünsche vorzugehen.

joinedload ist etwas dezenter. Es ist nur im Fall einer Sammlung verboten, bei der eine primäre Zeile möglicherweise mehrere zugeordnete Zeilen hat. Angenommen, Ihre Abfrage erzeugt Rohergebnisse wie diese, wobei A und B Primärschlüssel aus verschiedenen Tabellen sind:

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

Diese holen Sie sich nun mit yield_per(3) . Das Problem ist, dass SQLAlchemy nur begrenzen kann, wie viel es nach Zeilen abruft , aber es muss Objekte zurückgeben . Hier sieht SQLAlchemy nur die ersten drei Zeilen, also erstellt es ein A Objekt mit Schlüssel 1 und drei B Kinder:1, 2 und 3.

Wenn es den nächsten Stapel lädt, möchte es einen neuen A erstellen Objekt mit Schlüssel 1 ... ah, aber es hat bereits eines davon, also muss es nicht erneut erstellt werden. Das zusätzliche B , 4, geht verloren. (Also nein, sogar das Lesen verbundener Sammlungen mit yield_per ist unsicher – Teile Ihrer Daten könnten verloren gehen.)

Sie könnten sagen „Nun, lesen Sie einfach weiter Zeilen, bis Sie ein vollständiges Objekt haben“ – aber was ist, wenn dieses A hat hundert Kinder? Oder eine Million? SQLAlchemy kann vernünftigerweise nicht garantieren, dass es tun kann, was Sie gefragt haben und korrekte Ergebnisse liefern, also weigert es sich, es zu versuchen.

Denken Sie daran, dass die DBAPI so konzipiert ist, dass alle Datenbank kann mit derselben API verwendet werden, auch wenn diese Datenbank nicht alle DBAPI-Funktionen unterstützt. Bedenken Sie, dass die DBAPI um Cursor herum entwickelt wurde, aber MySQL keine Cursor! Die DBAPI-Adapter für MySQL müssen sie stattdessen vortäuschen.

Also während cursor.fetchmany(100) wird funktionieren , können Sie von die MySQLdb Quellcode dass es nicht faul vom Server holt; Es holt alles in eine große Liste und gibt dann einen Slice zurück, wenn Sie fetchmany aufrufen .

Was für psycopg2 unterstützt echtes Streaming, bei dem die Ergebnisse dauerhaft gespeichert werden auf dem Server, und Ihr Python-Prozess sieht nur wenige davon gleichzeitig.

Sie können immer noch yield_per verwenden mit MySQLdb , oder jede andere DBAPI; Das ist der springende Punkt beim Design der DBAPI. Sie müssen die Speicherkosten für alle Rohzeilen bezahlen, die in der DBAPI versteckt sind (die Tupel sind, ziemlich billig), aber auch werden Sie das nicht tun müssen für alle ORM-Objekte gleichzeitig bezahlen.