2013-07-25 6 views
21

Beide Methoden geben eine Liste der zurückgegebenen Elemente der Abfrage zurück, habe ich hier etwas verpasst? oder haben sie tatsächlich identische Gebräuche? irgendwelche Unterschiede leistungsmäßig?cursor.fetchall() vs Liste (Cursor) in Python

Antwort

40

Wenn Sie die Standard-Cursor verwenden, eine MySQLdb.cursors.Cursor, die gesamte Ergebnismenge auf der Client-Seite gespeichert wird (das heißt in einer Python-Liste) durch die Zeit, die cursor.execute() ist abgeschlossen.

Deshalb, auch wenn Sie

for row in cursor: 

verwenden, werden Sie keine Reduzierung des Speicherbedarfs bekommen sein. Die gesamte Ergebnismenge wurde bereits in einer Liste gespeichert (siehe self._rows in MySQLdb/cursors.py).

Wenn Sie jedoch einen SSCursor oder SSDictCursor verwenden:

import MySQLdb 
import MySQLdb.cursors as cursors 

conn = MySQLdb.connect(..., cursorclass=cursors.SSCursor) 

dann die Ergebnismenge wird in dem Server, mysqld gespeichert. Jetzt können Sie

cursor = conn.cursor() 
cursor.execute('SELECT * FROM HUGETABLE') 
for row in cursor: 
    print(row) 

schreiben und die Zeilen werden eine nach der einem vom Server geholt werden, also nicht Python erfordert zunächst eine riesige Liste von Tupeln zu bauen und damit auf dem Gedächtnis zu speichern.

Ansonsten, wie bereits erwähnt, sind cursor.fetchall() und im Wesentlichen gleich.

2

list(cursor) funktioniert, weil ein Cursor ein iterabler ist; Sie können auch cursor in einer Schleife verwenden:

for row in cursor: 
    # ... 

Eine gute Datenbankadapter Implementierung Reihen in Chargen vom Server holen wird, benötigt auf dem Speicherbedarf Einsparung, da es nicht in das voll Ergebnis auf halten müssen Erinnerung. cursor.fetchall()hat, um stattdessen die vollständige Liste zurückzugeben.

Es ist wenig sinnvoll, list(cursor) über cursor.fetchall() zu verwenden; Der End-Effekt ist dann in der Tat der gleiche, aber Sie haben eine Gelegenheit verschwendet, stattdessen Ergebnisse zu streamen.

+0

* "Es hat wenig Sinn, die list (cursor) über cursor.fetchall() zu verwenden; der End-Effekt ist dann tatsächlich derselbe, aber Sie haben eine Gelegenheit verschwendet, stattdessen Ergebnisse zu streamen." * - wahr für die meisten Implementierungen der Python-Datenbank-API. Weitaus weniger zutreffend im speziellen Fall von MySQLdb oder seinem Nachfolger, PyMySQL, wo 'cursor.fetchall()' einen inkonsistenten Rückgabetyp hat (was bedeutet, dass immer die Verwendung von 'list (cursor)' Ihre Möglichkeiten reduziert und einen TypeError verursacht) und die meisten Cursor-Unterklassen streamen beim Überschleifen nicht, sondern lesen alle Ergebnisse in den Speicher, bevor sie das erste Ergebnis liefern. –

+0

@MarkAmery: weshalb ich die Worte "eine gute Datenbankadapterimplementierung" sorgfältig verwendet habe. Ich vermutete, dass die vorhandenen MySQL-Implementierungen alle Ergebnisse im Voraus abgerufen haben, als ich den Beitrag geschrieben habe. –

9

cursor.fetchall() und sind im Wesentlichen gleich. Die andere Option ist es, nicht eine Liste abgerufen werden, und stattdessen nur eine Schleife über das nackte Cursor-Objekt:

for result in cursor: 

Dies kann effizienter sein, wenn die Ergebnismenge groß ist, da sie nicht das ganze Ergebnis zu holen haben setze und behalte alles im Speicher; es kann nur inkrementell jedes Element erhalten (oder in kleineren Batches stapelweise).

+1

Dies gilt für die meisten [PEP 249] (https://www.python.org/dev/peps/pep-0249) Implementierungen, aber nicht für MySQLdb oder PyMySQL, wobei 'list (cursor)' wohl vorzuziehen ist ' cursor.fetchall() '(weil letzterer entweder eine Liste oder ein Tupel inkonsistent zurückgibt, während ersteres immer eine Liste zurückgibt) und die meisten Cursorimplementierungen * die gesamte Ergebnismenge in den Speicher holen, sobald Sie mit der Iteration beginnen. –

3

A (MySQLdb/PyMySQL spezifisch) Unterschied bemerkenswert, bei Verwendung eines DictCursor ist, dass list(cursor) werden Sie immer eine Liste geben, während cursor.fetchall() gibt Ihnen eine Liste es sei denn die Ergebnismenge leer ist, wobei in diesem Fall gibt es Ihnen ein leeres Tupel. Dies war der Fall in MySQLdb und bleibt in dem neueren Stand PyMySQL der Fall, wo es aus Gründen der Abwärtskompatibilität will not be fixed ist.Während dieser isn't a violation of Python Database API Specification, ist es immer noch überraschend und kann leicht zu einem Typ Fehler führen, verursacht durch falsche Annahme, dass das Ergebnis eine Liste ist, anstatt nur eine Sequenz.

Angesichts der oben genannten, ich schlage vor, immer über cursor.fetchall(), um zu vermeiden, immer von einem mysteriösen Typ Fehler in der Rand Fall, wo Ihre Ergebnismenge ist leer.

Verwandte Themen