Par défaut, les jeux de résultats MySQL sont entièrement récupérés sur le serveur avant toute intervention. Dans le cas de jeux de résultats volumineux, cela devient inutilisable. Je voudrais plutôt récupérer les lignes une par une sur le serveur.
En Java, en suivant les instructions ici (sous "ResultSet"), je crée une déclaration comme celle-ci :
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
Cela fonctionne très bien en Java. Ma question est la suivante : existe-t-il un moyen de faire la même chose en Python ?
J'ai essayé de limiter la requête à 1000 lignes à la fois, comme ceci :
start_row = 0
while True:
cursor = conn.cursor()
cursor.execute("SELECT item FROM items LIMIT %d,1000" % start_row)
rows = cursor.fetchall()
if not rows:
break
start_row += 1000
# Do something with rows...
Toutefois, plus la valeur de start_row est élevée, plus le processus semble lent.
Et non, utiliser fetchone()
au lieu de fetchall()
ne change rien.
Clarification :
Le code naïf que j'utilise pour reproduire ce problème ressemble à ceci :
import MySQLdb
conn = MySQLdb.connect(user="user", passwd="password", db="mydb")
cur = conn.cursor()
print "Executing query"
cur.execute("SELECT * FROM bigtable");
print "Starting loop"
row = cur.fetchone()
while row is not None:
print ", ".join([str(c) for c in row])
row = cur.fetchone()
cur.close()
conn.close()
Sur une table de ~700 000 lignes, ce code s'exécute rapidement. Mais sur une table de ~9 000 000 de lignes, il affiche "Executing Query" et se bloque ensuite pendant un long moment. C'est pourquoi cela ne fait aucune différence si j'utilise fetchone()
ou fetchall()
.