2011-09-19 3 views
1

J'ai un jeu de résultats de requête de ~ 9 millions de lignes.En utilisant Python/PyGreSQL, comment gérer efficacement un grand ensemble de résultats?

que je dois faire un peu de traitement pour chaque ligne, et le code le fait déjà:

query = conn.query(sql) 
results = query.getresult() 

for row in results: 
    # blah 

Je ne suis pas sûr, mais je pense que getresult() tire vers le bas l'ensemble des résultats. Est-ce le cas? J'imagine qu'il y a un moyen de tirer seulement des morceaux du jeu de résultats à travers le fil comme nécessaire, mais je n'ai pas vu immédiatement quelque chose comme ça dans les docs du module pg.

Est-il possible de faire cela avec le module pgdb ou une autre approche? Mes préoccupations concernent la mémoire sur la machine d'application - je préférerais ne pas charger des millions de lignes en mémoire en une seule fois si je peux l'aider.

Cela vaut-il même la peine de s'inquiéter?

+0

Selon les documents pygresql, getresult renvoie un objet pyquery, avec différentes listes contenant toutes les données pour la requête associée. Vous aurez besoin de voir si l'une des bibliothèques d'accès db alternatives de python inclut un itérateur pour les résultats de la requête. –

Répondre

2

Si elle est après la Python Database API spec, vous pouvez utiliser un curseur:

curs = conn.cursor() 
curs.execute('select * from bigtable') 

puis utilisez curs.fetchone() ou curs.fetchmany(chunksize)

+0

J'ai utilisé 'pour row dans iter (curs.fetchone()):' - c'était peut-être plus explicite? Cela fonctionne comme prévu. –

+0

@anonymous: ???Si elle suit l'API DB, curs.fetchone() récupérera la première ligne. Itérer sur cela vous donne les valeurs de colonne de la première rangée. Peut-être que vous vouliez dire 'pour row dans iter (curs.fetchone, None):' –

0

Je ne sais pas comment, mais getresult() se comporte une autre option serait PL/Python:

Le langage procédural PL/Python permet aux fonctions de PostgreSQL à écrire dans le langage Python.

Cela vous permettrait de travailler directement dans la base de données. Cela pourrait ne pas convenir à ce que vous devez faire, mais cela vaut le coup d'oeil.

1

pgdb « de les curseurs sont itérateurs

cursor = conn.cursor() 
cursor.execute(sql) 

for row in cursor: 
    # do something with row 

conn est créé à partir pgdb.connect(...)

+0

Aidez-moi à comprendre: étant un «itérateur», cela implique-t-il que le jeu de résultats entier n'est * pas * chargé en mémoire, mais uniquement extrait du serveur postgres selon les besoins (à chaque itération)? –

+0

@anonymouscoward: oui; 'cursor.next()' appelle simplement 'fetchone()' et soulève 'StopIteration' s'il n'y a pas de résultat. Il est probablement plus pythonique de traiter le curseur comme un itérateur que d'appeler manuellement 'fetchone()'. – geoffspear

0

Utilisez cursor.fetchmany() et assurez-vous que vous définissez explicitement arraysize pour gérer les ensembles de lignes qui vous donnent l'équilibre dont vous avez besoin entre les performances et l'utilisation de la mémoire.

J'ai écrit des travaux dans cx_Oracle (qui utilise également la spécification DB-API) et l'utilise pour déplacer des tables de plusieurs milliards de lignes sur le réseau par lots de 20 000 enregistrements. Cela prend du temps, mais je ne souffle pas sur la mémoire de mon serveur, que ce soit du côté de la source ou de la cible.

Questions connexes