2009-01-17 23 views
15

He estado usando python con RDBMS '(MySQL y PostgreSQL), y he notado que realmente no entiendo cómo usar un cursor.¿Cómo funcionan los cursores en la DB-API de Python?

Por lo general, uno tiene su guión conectarse a la base de datos a través de un cliente de DB-API (como psycopg2 o MySQLdb):

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

Y entonces se crea un cursor:

cursor = connection.cursor() 

Y luego uno puede emitir consultas y comandos:

cursor.execute("SELECT * FROM etc") 

Ahora, ¿dónde está el resultado de la consulta, me pregunto? ¿está en el servidor? o un poco sobre mi cliente y un poco sobre mi servidor? Y luego, si es necesario acceder a algunos resultados, buscamos a ellos:

rows = cursor.fetchone() 

o

rows = cursor.fetchmany() 

Ahora digamos que, no recuperar todas las filas, y decidir ejecutar otra consulta, ¿Qué pasará con los resultados anteriores? Es su una sobrecarga.

Además, debería crear un cursor para cada forma de comando y reutilizarlo continuamente para esos mismos comandos de alguna manera; Dirijo psycopg2 de alguna manera puede optimizar los comandos que se ejecutan muchas veces, pero con diferentes valores, ¿cómo y lo vale?

Thx

+1

Re: mejores prácticas para los cursores, de las preguntas más frecuentes (http://initd.org/psycopg/docs/faq.html): "Nuestra sugerencia es crear casi siempre un cursor nuevo y deshacerse de los antiguos tan pronto como el ya no se requieren datos (call close() en ellos.) La única excepción son los bucles estrechos donde uno usualmente usa el mismo cursor para un conjunto completo de INSERT o UPDATE. " –

Respuesta

3

Ya, ya sé que es meses de edad: P

aparece cursor

de DB-API para estar cerca el modelo después de los cursores SQL. Gestión de recursos AFA (filas), DB-API no especifica si el cliente debe recuperar todas las filas o DECLARAR un cursor SQL real. Siempre que las interfaces fetchXXX hagan lo que se supone que deben, DB-API está contenta.

Los cursores AFA psycopg2 están preocupados (como bien puede saber), los "cursores DB-API sin nombre" buscarán el conjunto de resultados completo - AFAIK almacenado en la memoria mediante libpq. los "cursores denominados DB-API" (un concepto de psycopg2 que puede no ser portátil), solicitarán las filas bajo demanda (métodos fetchXXX).

Como se menciona por "unbeknown", executemany se puede utilizar para optimizar varias ejecuciones del mismo comando. Sin embargo, no se adapta a la necesidad de declaraciones preparadas; cuando las ejecuciones repetidas de una instrucción con diferentes conjuntos de parámetros no son directamente secuenciales, executemany() funcionará tan bien como execute(). DB-API "proporciona" a los autores de controladores la capacidad de almacenar en caché las sentencias ejecutadas, pero su implementación (¿cuál es el alcance/duración de la declaración?) No está definida, por lo que es imposible establecer expectativas en las implementaciones DB-API.

Si está cargando muchos datos en PostgreSQL, recomiendo encarecidamente intentar encontrar una manera de usar COPY.

1

Suponiendo que está usando PostgreSQL, los cursores probablemente se acaba de implementar el uso de la API nativa del cursor de la base de datos. Es posible que desee consultar el código fuente pg8000, un módulo puro Python PostgreSQL DB-API, para ver cómo maneja los cursores. También puede mirar the PostgreSQL documentation for cursors.

1

Cuando mira aquí en el mysqldb documentation puede ver que implementaron diferentes estrategias para los cursores. Entonces la respuesta general es: depende.

Editar: Aquí está el mysqldb API documentation. Hay alguna información sobre cómo se comporta cada tipo de cursor. El cursor estándar almacena el conjunto de resultados en el cliente. Así que supongo que hay una sobrecarga si no recuperas todas las filas de resultados, porque incluso las filas que no recuperas deben transferirse al cliente (posiblemente a través de la red). Mi suposición es que no es tan diferente de postgresql.

Cuando desee optimizar las declaraciones de SQL a las que llama repetidamente con muchos valores, debe ver cursor.executemany(). Se prepara una instrucción SQL para que no necesita ser analizada cada vez que se llame:

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