2015-02-05 15 views
8

Sto utilizzando psycopg2 per eseguire una query su un database Postgresql e provare a elaborare tutte le righe da una tabella con circa 380 milioni di righe. Ci sono solo 3 colonne (id1, id2, count) tutto il tipo intero. Tuttavia, quando eseguo la query di selezione diretta di seguito, il processo Python inizia a consumare sempre più memoria, finché non viene ucciso dal sistema operativo.Psycopg2 utilizza la memoria su query di selezione ampia

Minimal esempio di lavoro (supponendo che esista mydatabase e contiene una tabella denominata miatabella):

import psycopg2 
conn = psycopg2.connect("dbname=mydatabase") 
cur = conn.cursor() 
cur.execute("SELECT * FROM mytable;") 

A questo punto il programma inizia a consumare memoria.

Ho dato un'occhiata e il processo Postgresql si sta comportando bene. Sta usando un bel po 'di CPU, che va bene, e una quantità molto limitata di memoria.

Mi aspettavo che psycopg2 restituisca un iteratore senza tentare di bufferizzare tutti i risultati dalla selezione. Potrei quindi utilizzare cur.fetchone() ripetutamente per elaborare tutte le righe.

Quindi, come selezionare da una tabella di riga 380M senza utilizzare la memoria disponibile?

risposta

12

È possibile utilizzare server side cursors.

cur = conn.cursor('cursor-name') # server side cursor 
cur.itersize = 10000 # how much records to buffer on a client 
cur.execute("SELECT * FROM mytable;") 
+0

Grande, grazie per quello! Ho intenzione di apportare alcune modifiche per migliorare leggermente la spiegazione e quindi accettare. – Carl

+0

Questo cursore esiste nel server PostgreSQL o nel client Python? DECLARE cursor_name CURSOR FOR SELECT * FROM mytable; –

+0

@FrankHeikens Tutto è fatto dal lato client Python in questo caso. Nessun cursore esiste sul lato server. – Carl

0

Un altro modo di utilizzare i cursori laterali di server:

with psycopg2.connect(database_connection_string) as conn: 
    with conn.cursor(name='name_of_cursor') as cursor: 

     cursor.itersize = 20000 

     query = "SELECT * FROM ..." 
     cursor.execute(query) 

     for row in cursor: 
      # process row 

psycopg2 preleverà itersize righe al cliente alla volta. Una volta che il ciclo for esaurisce quel batch, verrà recuperato il successivo.