33 Stimmen

Wie funktionieren Cursors in der DB-API von Python?

Ich habe Python mit RDBMS' (MySQL und PostgreSQL) verwendet, und ich habe bemerkt, dass ich wirklich nicht verstehen, wie man einen Cursor zu verwenden.

Normalerweise lässt man sein Skript über eine Client-DB-API (wie psycopg2 oder MySQLdb) mit der DB verbinden:

connection = psycopg2.connect(host='otherhost', etc)

Und dann erstellt man einen Cursor:

cursor = connection.cursor()

Und dann kann man Abfragen und Befehle erteilen:

cursor.execute("SELECT * FROM etc")

Nun frage ich mich, wo das Ergebnis der Abfrage liegt. Ist es auf dem Server oder ein wenig auf meinem Client und ein wenig auf meinem Server? Und dann, wenn wir auf einige Ergebnisse zugreifen müssen, holen wir sie ab:

rows = cursor.fetchone() 

oder

rows = cursor.fetchmany()

Angenommen, ich kann nicht alle Zeilen abrufen und beschließe, eine weitere Abfrage auszuführen, was geschieht dann mit den vorherigen Ergebnissen? Gibt es einen Overhead.

Auch sollte ich einen Cursor für jede Form des Befehls und kontinuierlich wiederverwenden es für diese gleichen Befehle irgendwie; Ich Kopf psycopg2 kann irgendwie optimieren Befehle, die viele Male ausgeführt werden, aber mit unterschiedlichen Werten, wie und ist es wert?

Vielen Dank

9voto

jwp Punkte 386

Ja, ich weiß, es ist schon Monate alt :P

Der Cursor von DB-API scheint eng an SQL-Cursoren angelehnt zu sein. Die Verwaltung der AFA-Ressourcen (Zeilen) ist betroffen, DB-API gibt nicht an, ob der Client alle Zeilen abrufen muss oder ob er einen tatsächlichen SQL-Cursor DECLARE . Solange die fetchXXX-Schnittstellen das tun, was sie tun sollen, ist die DB-API zufrieden.

AFA psycopg2 Cursors betroffen sind (wie Sie vielleicht wissen), "unnamed DB-API cursors" holen die gesamte Ergebnismenge - AFAIK gepuffert im Speicher von libpq. "benannte DB-API-Cursoren" (ein psycopg2-Konzept, das möglicherweise nicht portabel ist), fordern die Zeilen bei Bedarf an (fetchXXX-Methoden).

Wie von "unbeknown" angeführt, kann executemany verwendet werden, um mehrere Durchläufe desselben Befehls zu optimieren. Es berücksichtigt jedoch nicht den Bedarf an vorbereiteten Anweisungen; wenn die wiederholte Ausführung einer Anweisung mit unterschiedlichen Parametersätzen nicht direkt aufeinander folgt, funktioniert executemany() genauso gut wie execute(). Die DB-API "bietet" den Autoren von Treibern die Möglichkeit, ausgeführte Anweisungen zwischenzuspeichern, aber ihre Implementierung (was ist der Umfang/die Lebensdauer der Anweisung?) ist nicht definiert, so dass es unmöglich ist, Erwartungen für verschiedene DB-API-Implementierungen festzulegen.

Wenn Sie viele Daten in PostgreSQL laden, würde ich dringend empfehlen, einen Weg zu finden, COPY zu verwenden.

2voto

kquinn Punkte 10083

In der Annahme, dass Sie PostgreSQL verwenden, sind die Cursor wahrscheinlich nur mit der datenbankeigenen Cursor-API implementiert. Vielleicht möchten Sie sich den Quellcode für pg8000 , ein reines Python-PostgreSQL-DB-API-Modul, um zu sehen, wie es mit Cursoren umgeht. Vielleicht möchten Sie auch einen Blick auf die PostgreSQL-Dokumentation für Cursoren .

1voto

Wenn Sie sich hier die mysqldb-Dokumentation können Sie sehen, dass sie unterschiedliche Strategien für Cursors implementiert haben. Die allgemeine Antwort lautet also: Es kommt darauf an.

Edit: Hier ist die mysqldb-API-Dokumentation . Es gibt einige Informationen darüber, wie sich die einzelnen Cursortypen verhalten. Der Standardcursor speichert die Ergebnismenge im Client. Ich nehme also an, dass es einen Overhead gibt, wenn man nicht alle Ergebniszeilen abruft, da auch die Zeilen, die man nicht abruft, zum Client übertragen werden müssen (möglicherweise über das Netzwerk). Meine Vermutung ist, dass es sich nicht so sehr von Postgresql unterscheidet.

Wenn Sie SQL-Anweisungen optimieren wollen, die Sie wiederholt mit vielen Werten aufrufen, sollten Sie sich cursor.executemany() ansehen. Sie bereitet eine SQL-Anweisung so vor, dass sie nicht bei jedem Aufruf neu geparst werden muss:

cur.executemany('INSERT INTO mytable (col1, col2) VALUES (%s, %s)',
                [('val1', 1), ('val2', 2)])

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X