2008-08-03 31 views
34

Il existe plusieurs façons d'itérer sur un ensemble de résultats. Quels sont les compromis de chacun?cx_Oracle: Comment parcourir une série de résultats?

+1

Il y a des exceptions à cette règle, mais la règle générale est: s'il y a plus d'une façon de le faire, c'est probablement parce que chaque façon est adaptée à différentes situations.Sinon, il n'y aurait qu'un seul moyen. –

Répondre

34

La méthode canonique consiste à utiliser l'itérateur de curseur intégré.

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

Vous pouvez utiliser fetchall() pour obtenir toutes les lignes à la fois.

for row in curs.fetchall(): 
    print row 

Il peut être pratique d'utiliser pour créer une liste Python contenant les valeurs renvoyées:

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

Cela peut être utile pour les jeux de résultats plus petits, mais peut avoir des effets secondaires néfastes si le jeu de résultats est large.

  • Vous devez attendre le résultat complet prévu à retourner à votre processus client.

  • Vous pouvez consommer beaucoup de mémoire dans votre client pour contenir la liste déroulante.

  • Python peut mettre un certain temps à construire et à déconstruire la liste que vous allez immédiatement rejeter de toute façon.


Si vous savez qu'il ya une seule ligne étant de retour dans le jeu de résultats, vous pouvez appeler fetchone() pour obtenir la seule ligne.

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

Enfin, vous pouvez boucler sur le jeu de résultats la récupération d'une ligne à la fois. En général, il n'y a aucun avantage particulier à faire cela en utilisant l'itérateur.

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

sur la deuxième méthode, que se passe-t-il si vous utilisez un SScursor? cela va-t-il manger beaucoup de mémoire? – Sylvain

+0

Je pense que SScursor est pour MySQL. Mais tout ce qui a un fetchall() aura probablement la même utilisation de la mémoire, car il retourne une liste de toutes les lignes retournées. –

4

Il y a aussi la façon dont psyco-pg semble le faire ... D'après ce que je comprends, il semble créer des lignes proxies comme dictionnaire de carte recherche clé dans le bloc de mémoire renvoyée par la requête. Dans ce cas, aller chercher toute la réponse et travailler avec un proxy-factory similaire sur les lignes semble être une idée utile. Quand on y pense, ça ressemble plus à Lua qu'à Python.

En outre, cela devrait être applicable à toutes les interfaces PEP-249 DBAPI2.0, pas seulement Oracle, ou avez-vous dire que le plus rapide utilisant Oracle?

21

Mon chemin préféré est l'itérateur du curseur, mais en définissant d'abord la propriété arraysize du curseur.

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

Dans cet exemple, cx_Oracle va chercher les lignes de Oracle 256 lignes à la fois, ce qui réduit le nombre de voyages rondes de réseau qui doivent être effectuées

+2

Lors de mes tests (sur une base de données connectée par LAN), cela semblait réellement donner une vitesse identique (encore plus lente, en quelques itérations) comparé à faire 'fetchone()' à plusieurs reprises. Je le faisais avec environ 12000 entrées ... Très étrange! –

+0

La seule façon dont je sache, et je ne suis en aucun cas un expert Oracle, que ce serait le cas si votre requête retourne des caractères de type objet grand (CLOB) ou BLOB (binary large object). AFAI Comprenez-le, la lecture de ces objets nécessite un autre aller-retour réseau sur le serveur db pour chaque enregistrement; ce qui signifie qu'avec fetchmany vous obtenez réellement le pire des deux mondes. – asmoore82

+0

Pour cx_Oracle, se connecter à une base de données 12c avec des types de colonnes standard (pas de clobs etc) j'obtiens une accélération mais seulement si je mets arraysize * avant * l'exécution de la requête. Les nombres précis seront évidemment massivement dépendants du contexte mais pour donner une idée de l'ordre de grandeur des changements, ma requête (retournant 5 colonnes) avec arraysize = 50 (défaut) donne 3.75us par ligne. Diminuer l'arraysize à 1 donne 70us. Augmenter la taille de l'écran à 1000 donne 800ns – FredL