2011-01-28 3 views
4

Je suis en train de réaliser ce qui suit en utilisant Python et l'interface MySQLdb:requêtes imbriquées en utilisant MySQLdb

  1. Lire le contenu d'une table qui a quelques millions de lignes.
  2. Procédé et modifier la sortie de chaque ligne.
  3. Mettez les lignes modifiées dans une autre table.

Il me semble logique de parcourir chaque ligne, de traiter à la volée et d'insérer chaque nouvelle ligne dans la nouvelle table à la volée.

Cela fonctionne:

import MySQLdb 
import MySQLdb.cursors 

conn=MySQLdb.connect(
    host="somehost",user="someuser", 
    passwd="somepassword",db="somedb") 

cursor1 = conn.cursor(MySQLdb.cursors.Cursor) 
query1 = "SELECT * FROM table1" 
cursor1.execute(query1) 

cursor2 = conn.cursor(MySQLdb.cursors.Cursor) 

for row in cursor1: 
    values = some_function(row) 
    query2 = "INSERT INTO table2 VALUES (%s, %s, %s)" 
    cursor2.execute(query2, values) 

cursor2.close() 
cursor1.close() 
conn.commit() 
conn.close() 

Mais cela est lent et la consommation de mémoire car il utilise un curseur côté client pour la requête SELECT. Si je l'utilise à la place un curseur côté serveur pour la requête SELECT:

cursor1 = conn.cursor(MySQLdb.cursors.SSCursor) 

Puis-je obtenir une erreur 2014:

Exception _mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now") in <bound method SSCursor.__del__ of <MySQLdb.cursors.SSCursor object at 0x925d6ec>> ignored 

Il ne semble pas comme commencer un autre curseur tout en évoluant sur une curseur côté serveur. Ce qui semble me laisser coincé avec un itérateur côté client très lent.

Des suggestions?

+2

Bien que sans rapport avec votre problème technique (qui est que vous devez lire le tampon entier jeu de résultats avant de lancer une autre requête), êtes-vous sûr que vous ne pouvez pas réécrire ce code comme une seule requête 'INSERT INTO ... SELECT', où' SELECT' exécute la logique que 'some_function' devait effectuer? MySQL peut faire beaucoup de choses à l'intérieur d'une requête. –

+0

Avec la table avec laquelle je travaille actuellement, je pourrais probablement, oui. Le plus gros problème (que j'aurais dû mentionner dans la question - semble toujours manquer quelque chose!) Est que j'aurai beaucoup plus de ces tables à lire dans le futur, et je ne sais pas quelles sont les fonctions dont j'ai besoin pour effectuer sur ceux encore. Je pense que le traitement en Python plutôt qu'en MySQL me permettrait de me prémunir contre tout ce qui pourrait arriver. Merci pour le commentaire cependant - je devrais avoir recours au traitement de MySQL si nécessaire. – edanfalls

Répondre

1

Vous avez besoin d'une connexion séparée à la base de données, étant donné que la première connexion est bloqué avec le streaming ResultSet, vous ne pouvez pas exécuter la requête d'insertion.

Essayez ceci:

import MySQLdb 
import MySQLdb.cursors 

conn=MySQLdb.connect(
    host="somehost",user="someuser", 
    passwd="somepassword",db="somedb") 

cursor1 = conn.cursor(MySQLdb.cursors.SSCursor) 
query1 = "SELECT * FROM table1" 
cursor1.execute(query1) 

insertConn=MySQLdb.connect(
    host="somehost",user="someuser", 
    passwd="somepassword",db="somedb") 
cursor2 = inserConn.cursor(MySQLdb.cursors.Cursor) 

for row in cursor1: 
    values = some_function(row) 
    query2 = "INSERT INTO table2 VALUES (%s, %s, %s)" 
    cursor2.execute(query2, values) 

cursor2.close() 
cursor1.close() 
conn.commit() 
conn.close() 
insertConn.commit() 
insertConn.close() 
Questions connexes