2009-01-17 9 views
15

Ich habe Python mit RDBMS '(MySQL und PostgreSQL) verwendet, und ich habe festgestellt, dass ich wirklich nicht verstehe, wie man einen Cursor verwendet.Wie funktionieren Cursor in Pythons DB-API?

Normalerweise man habe sein Skript über einen Client DB-API (wie psycopg2 oder MySQLdb) an die DB verbinden:

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

Und dann schafft man einen Cursor:

cursor = connection.cursor() 

Und dann man kann Abfragen und Befehle ausgeben:

cursor.execute("SELECT * FROM etc") 

Jetzt wo ist das Ergebnis der Abfrage, frage ich mich? ist es auf dem Server? oder ein wenig auf meinem Client und ein bisschen auf meinem Server? Und dann, wenn wir einige Ergebnisse zugreifen müssen, holen wir ‚em:

rows = cursor.fetchone() 

oder

rows = cursor.fetchmany() 

Jetzt können sagen, ich rufe nicht alle Zeilen und entscheiden, eine andere Abfrage auszuführen, Was wird mit den vorherigen Ergebnissen passieren? Ist das ein Overhead?

Auch sollte ich einen Cursor für jede Form von Befehl erstellen und ihn für diese Befehle irgendwie immer wiederverwenden; Ich Kopf psycopg2 kann irgendwie Befehle optimieren, die viele Male ausgeführt werden, aber mit unterschiedlichen Werten, wie und ist es das wert?

Thx

+1

Re: Best Practices für die Cursor, aus der FAQ (http://initd.org/psycopg/docs/faq.html): „Unser Vorschlag fast immer auf einen neuen Cursor erstellen und alte, sobald der entsorgen Daten sind nicht mehr erforderlich (close close() auf ihnen.) Die einzige Ausnahme sind enge Schleifen, wo man normalerweise den gleichen Cursor für eine ganze Reihe von INSERTs oder UPDATEs verwendet. " –

Antwort

3

ya, ich weiß, es ist Monate alt: P

DB-API des Cursors eng scheint modelliert zu werden nach SQL-Cursor. AFA Ressourcen (Zeilen) Management ist betroffen, DB-API gibt nicht an, ob der Client alle Zeilen abrufen muss oder DECLARE einen tatsächlichen SQL-Cursor. Solange die fetchXXX-Schnittstellen das machen, was sie sollen, ist DB-API glücklich.

AFA psycopg2-Cursor sind betroffen (wie Sie vielleicht wissen), "unbenannte DB-API-Cursor" wird die gesamte Ergebnismenge abrufen - AFAIK im Speicher von libpq gepuffert. "benannte DB-API-Cursor" (ein psycopg2-Konzept, das möglicherweise nicht portierbar ist), fordert die Zeilen auf Anforderung (fetchXXX-Methoden) an.

Wie von "unknownown" zitiert, kann Executemany verwendet werden, um mehrere Läufe desselben Befehls zu optimieren. Es berücksichtigt jedoch nicht die Notwendigkeit von vorbereiteten Aussagen; Wenn die Ausführung einer Anweisung mit verschiedenen Parametersätzen nicht direkt sequentiell ist, wird executemany() genauso gut funktionieren wie execute(). DB-API bedeutet „liefern“ Treiber Autoren mit der Fähigkeit ausgeführten Anweisungen cachen, aber die Umsetzung (was ist der Umfang/Lebensdauer der Aussage?) Ist nicht definiert, so dass es unmöglich ist, die Erwartungen über DB-API-Implementierungen zu setzen.

Wenn Sie viele Daten in PostgreSQL laden, empfehle ich Ihnen dringend, eine Möglichkeit zu finden, COPY zu verwenden.

1

Sie verwenden PostgreSQL Angenommen werden die Cursor wahrscheinlich nur implementiert die native Cursor API-Datenbank. Sie können den Quellcode für pg8000, ein reines Python PostgreSQL DB-API-Modul, betrachten, um zu sehen, wie es Cursor behandelt. Vielleicht möchten Sie auch auf the PostgreSQL documentation for cursors aussehen.

1

Wenn Sie hier auf die mysqldb documentation schauen, können Sie sehen, dass sie verschiedene Strategien für Cursor implementiert haben. Die allgemeine Antwort lautet also: Es kommt darauf an.

Edit: Hier ist die mysqldb API documentation. Es gibt einige Informationen, wie sich jeder Cursortyp verhält. Der Standard-Cursor speichert die Ergebnismenge im Client. Also nehme ich an, dass es einen Overhead gibt, wenn Sie nicht alle Ergebniszeilen abrufen, weil sogar die Zeilen, die Sie nicht abrufen, an den 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 möchten, die Sie wiederholt mit vielen Werten aufrufen, sollten Sie sich cursor.executemany() ansehen. Er bereitet eine SQL-Anweisung, so dass es nicht jedes Mal, wenn Sie es nennen analysiert werden muss:

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