2008-08-03 15 views
34

Es gibt mehrere Möglichkeiten, über eine Ergebnismenge zu iterieren. Was ist der Kompromiss von jedem?cx_Oracle: Wie wiederhole ich eine Ergebnismenge?

+1

Es gibt Ausnahmen, aber die allgemeine Faustregel gilt: ist: Wenn es mehr als einen Weg gibt, es zu tun, liegt es wahrscheinlich daran, dass jeder Weg für verschiedene Situationen geeignet ist.Sonst gäbe es nur einen Weg. –

Antwort

34

Die kanonische Methode besteht darin, den integrierten Cursor-Iterator zu verwenden.

curs.execute('select * from people') 
for row in curs: 
    print row 

können Sie fetchall() verwenden, um alle Zeilen auf einmal zu bekommen.

for row in curs.fetchall(): 
    print row 

Es kann zweckmäßig sein, diese zu verwenden, um eine Python-Liste enthält die Werte zu schaffen zurückgegeben:

curs.execute('select first_name from people') 
names = [row[0] for row in curs.fetchall()] 

Dies kann für kleinere Ergebnismengen sinnvoll sein, kann aber schlechte Nebenwirkungen haben, wenn die Ergebnismenge ist groß.

  • Sie haben für das gesamte Ergebnis warten auf Ihre Client-Prozess zurückgegeben werden.

  • Sie können in Ihrem Client viel Speicher verbrauchen, um die aufgebaute Liste zu halten.

  • Es kann eine Weile dauern, bis Python die Liste erstellt und dekonstruiert, die Sie sowieso sofort verwerfen werden.


Wenn Sie wissen, eine einzelne Zeile, die in der Folge gibt es wieder richten Sie fetchone() die einzige Reihe bekommen aufrufen können.

curs.execute('select max(x) from t') 
maxValue = curs.fetchone()[0] 

Schließlich kann man eine Schleife über die Ergebnismenge Abrufen einer Zeile zu einem Zeitpunkt. Im Allgemeinen hat dies keinen besonderen Vorteil gegenüber der Verwendung des Iterators.

row = curs.fetchone() 
while row: 
    print row 
    row = curs.fetchone() 
+1

über die zweite Methode, was ist, wenn Sie einen SScursor verwenden? Wird es noch viel Gedächtnis auffressen? – Sylvain

+0

Ich denke, SScursor ist für MySQL. Aber alles, was fetchall() hat, wird wahrscheinlich die gleiche Speicherbelegung haben, da es eine Liste aller zurückgegebenen Zeilen zurückgibt. –

4

dort ist auch die Art und Weise psyco-pg scheint es zu tun ... Von dem, was ich sammeln, so scheint es, Wörterbuch artige Zeilen Proxies erstellen Schlüsselsuche in den Speicherblock von der Abfrage zurückgegeben abzubilden. In diesem Fall scheint es nützlich zu sein, die ganze Antwort zu holen und mit einer ähnlichen Proxy-Factory über die Zeilen zu arbeiten. Wenn man darüber nachdenkt, fühlt es sich eher wie Lua als Python an.

Auch sollte dies für alle PEP-249 DBAPI2.0 Schnittstellen anwendbar sein, nicht nur Oracle, oder meinst du nur schnellste mit Oracle?

21

Mein bevorzugter Weg ist der Cursor-Iterator, aber zuerst die Eigenschaft arrayize des Cursors.

curs.execute('select * from people') 
curs.arraysize = 256 
for row in curs: 
    print row 

In diesem Beispiel wird cx_Oracle Reihen von Oracle holt 256 Zeilen zu einer Zeit, die Anzahl der Netzwerk-Rundfahrten zu reduzieren, die durchgeführt werden müssen, um

+2

In meinen Tests (in einer Datenbank, die durch LAN verbunden ist) schien dies tatsächlich identische (sogar langsamer, in ein paar Iterationen) Geschwindigkeit zu geben, verglichen mit dem wiederholten Ausführen von 'fetchone()'. Ich habe es mit ungefähr 12000 Einträgen gemacht ... Sehr merkwürdig! –

+0

Der einzige Weg, den ich kenne, und ich bin in keiner Weise ein Oracle-Experte, dass dies der Fall ist, wenn Ihre Abfrage Zeichen große Objekt (CLOB) oder binary Large Object (BLOB) Typen zurückgibt. AFAI: Wenn Sie diese Objekte lesen, ist für jeden Datensatz ein weiterer Netzwerkrundlauf zum Datenbankserver erforderlich. Das bedeutet, dass Sie mit fetchmany tatsächlich das Schlimmste aus beiden Welten bekommen. – asmoore82

+0

Für cx_Oracle, Verbindung zu einer 12c-Datenbank mit Standard-Spaltentypen (keine Clobs etc) Ich bekomme eine Beschleunigung, aber nur wenn ich Array-Größe * vor * die Abfrage ausführen. Genaue Zahlen werden offensichtlich massiv kontextabhängig sein, aber um eine Vorstellung von den Veränderungen der Größenordnung zu geben, ergibt meine Abfrage (die 5 Spalten zurückgibt) mit arraysize = 50 (Standard) 3,75us pro Zeile. Das Verringern von arrayize auf 1 ergibt 70us. Steigende Arraygröße auf 1000 ergibt 800ns – FredL

Verwandte Themen