2015-12-25 16 views
6

Uso Postgresql 9.4 per un database modello. Il mio tavolo si presenta un po 'come questo:Ottimizzazione delle prestazioni Postgresql e uso della memoria in un flusso di lavoro Python

CREATE TABLE table1 (
sid INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('table1_sid_seq'::regclass), 
col1 INT, 
col2 INT, 
col3 JSONB); 

mio Python 2.7 flusso di lavoro spesso assomiglia a questo:

curs.execute("SELECT sid, col1, col2 FROM table1") 
data = curs.fetchall() 
putback = [] 
for i in data: 
    result = do_something(i[1], i[2]) 
    putback.append((sid, result)) 
del data 
curs.execute("UPDATE table1 
       SET col3 = p.result 
       FROM unnest(%s) p(sid INT, result JSONB) 
       WHERE sid = p.sid", (putback,)) 

Questo funziona in genere abbastanza bene e in modo efficiente. Tuttavia, per le query di grandi dimensioni l'utilizzo della memoria Postgresql a volte passa attraverso il tetto (> 50 GB) durante il comando UPDATE e credo che venga ucciso da OS X, perché ottengo lo WARNING: terminating connection because of crash of another server process. Il mio Macbook Pro ha 16 GB di RAM e la query in questione ha 11 milioni di righe con circa 100 caratteri di dati da riscrivere.

mio postgresql.conf:

default_statistics_target = 50 
maintenance_work_mem = 512MB 
constraint_exclusion = on 
checkpoint_completion_target = 0.9 
effective_cache_size = 4GB 
work_mem = 256MB 
wal_buffers = 16MB 
checkpoint_segments = 128 
shared_buffers = 1024MB 
max_connections = 80 

Allora mi chiedo

  1. Perché la mia domanda consumando a volte eccessive quantità di RAM?
  2. Come posso controllare l'utilizzo della memoria e garantire comunque buone prestazioni?
  3. Esiste una buona guida o uno strumento per la regolazione di Postgresql?

Aggiornamento:
Sono abbastanza sicuro che @wildplasser individuato il mio problema. Nei commenti suggerisce di scaricare prima i dati nel database e di decomprimerlo da lì. Sfortunatamente non sono riuscito a capire come implementare la sua proposta. Se qualcuno ha un'idea su come farlo, la sua risposta sarà accettata volentieri.

+0

1) il tuo work_mem è (piuttosto) alto, e tu (probabilmente) non hai una struttura tabella. 2) progetta il tuo database 3) vedi 2 BTW: la tua query seleziona recupera * tutte * le righe (e non capisco la tua query di aggiornamento). – wildplasser

+0

Sì. Il tuo tavolo potrebbe sembrare un foglio di calcolo, non lo so. Sì. – wildplasser

+0

BTW: Non capisco una parola sulla tua roba di pitone, ma sembra * come se tu stia succhiando l'intero db-table in un set o array python, e usi quello (in forma esplosa) per aggiornare la stessa tabella. – wildplasser

risposta

1

mio soluzione è di affettare putback con una semplice funzione come proposto here:

def chunk(l, n): 
    n = max(1, n) 
    return [l[i:i + n] for i in range(0, len(l), n)] 

e poi

for chunk in chunk(putback, 250000): 
    curs.execute("UPDATE table1 
        SET col3 = p.result 
        FROM unnest(%s) p(sid INT, result JSONB) 
        WHERE sid = p.sid", (chunk,)) 

Questo funziona, cioè mantiene l'occupazione di memoria sotto controllo, ma non è molto elegante e lento di scaricare tutti i dati contemporaneamente, come faccio di solito.

Problemi correlati