2008-08-03 35 views
34

Hay varias formas de iterar sobre un conjunto de resultados. ¿Cuál es la compensación de cada uno?cx_Oracle: ¿Cómo puedo iterar sobre un conjunto de resultados?

+1

hay excepciones a esto, pero la regla general es: si hay más de una forma de hacerlo, es probable que sea porque cada forma es adecuada para diferentes situaciones.De lo contrario, solo habría una forma. –

Respuesta

34

La forma canónica es el uso de la incorporada en el iterador cursor.

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

Puede utilizar fetchall() para obtener todas las filas a la vez.

for row in curs.fetchall(): 
    print row 

Puede ser conveniente utilizar esto para crear una lista de Python que contiene los valores devueltos:

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

Esto puede ser útil para los conjuntos de resultados más pequeños, pero pueden tener efectos secundarios negativos si el conjunto de resultados es largo.

  • usted tiene que esperar para todo el conjunto de resultados a ser devuelto a su proceso del cliente.

  • Puede consumir mucha memoria en su cliente para contener la lista acumulada.

  • Python puede tardar un tiempo en construir y deconstruir la lista que de todos modos descartarás inmediatamente.


Si usted sabe que hay una sola fila de ser devuelto en el conjunto de resultados puede llamar fetchone() para obtener la hilera.

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

Por último, se puede iterar sobre el conjunto de resultados ir a buscar una fila a la vez. En general, no hay una ventaja particular al hacer esto sobre el uso del iterador.

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

sobre el segundo método, ¿y si usa un SScursor? ¿Todavía comerá mucha memoria? – Sylvain

+0

Creo que SScursor es para MySQL. Pero cualquier cosa que tenga un fetchall() probablemente tendrá el mismo uso de memoria, ya que devuelve una lista de todas las filas devueltas. –

4

Hay también la forma psyco-pg parece hacerlo ... Por lo que sé, parece crear diccionario-como proxies de fila para mapear el rastreo de teclas en el bloque de memoria devuelta por la consulta. En ese caso, buscar la respuesta completa y trabajar con una proxy-fábrica similar sobre las filas parece una idea útil. Ahora que lo pienso, se siente más como Lua que como Python.

Además, esto debería ser aplicable a todas las interfaces de PEP-249 DBAPI2.0, no sólo Oracle o Quiso decir simplemente más rápido utilizando Oracle ?

21

Mi forma preferida es el iterador del cursor, pero primero aplicar la propiedad arraysize del cursor.

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

En este ejemplo, cx_Oracle se extraen filas de Oracle 256 filas a la vez, reducir el número de idas y vueltas de red que deban llevarse a cabo

+2

En mis pruebas (en una base de datos conectada por LAN) esto realmente pareció dar velocidades idénticas (incluso más lentas, en un par de iteraciones) en comparación con hacer 'fetchone()' repetidamente. Lo estaba haciendo con aproximadamente 12000 entradas ... ¡Muy extraño! –

+0

La única forma que conozco, y de ningún modo soy un experto en Oracle, es que este sea el caso si su consulta devuelve tipos de objetos grandes (CLOB) o objetos binarios grandes (BLOB). AFAI Comprenda que leer estos objetos requiere otra red de ida y vuelta al servidor de db para cada registro; lo que significa que con fetchmany realmente obtienes lo peor de ambos mundos. – asmoore82

+0

Para cx_Oracle, conectando a una base de datos 12c con tipos de columnas estándar (sin huellas, etc.) obtengo una aceleración, pero solo si configuro * arraysize * antes * de ejecutar la consulta. Los números precisos obviamente dependerán masivamente del contexto, pero para dar una idea del orden de los cambios de magnitud, mi consulta (que devuelve 5 columnas) con arraysize = 50 (por defecto) da 3.75us por fila. Disminuir arraysize a 1 da 70us. El aumento de arraysize a 1000 da 800ns – FredL

Cuestiones relacionadas