2011-02-23 16 views
5

Sto compilando una tabella PostgreSQL con ~ 11.000.000 di righe che sono state selezionate in precedenza da un altro database. Sto usando Python e psycopg2. L'intero processo richiede circa 1,5 ore per essere completato. Tuttavia, dopo ~ 30 minuti ottengo l'eccezione "connessione chiusa in modo imprevisto". Il codice sorgente è simile al seguente:La connessione PostgreSQL si chiude in modo imprevisto quando si esegue un inserto grande

incursor = indb.cursor() 
incursor.execute("SELECT ...") 
indb.commit() # (1) close transaction 
outcursor = outdb.cursor() 
rows = 0 
for (col1, col2, col3) in incursor: # incursor contains ~11.000.000 rows 
    outcursor.execute("INSERT ...", (col1, col2, col3)) # This fails after ~30 minutes 
    row += 1 
    if row % 100 == 0: # (2) Write data every 100 rows 
     outcursor.close() 
     outdb.commit() 
     outcursor = outdb.cursor() 
incursor.close() 
outcursor.close() 
outdb.commit() 

ho inserito (1) e (2) dopo i primi tentativi non riusciti, partendo dal presupposto che una transazione aperta ha un limite di tempo superiore di circa 30 minuti o che un cursore ha un limite massimo di attesa inserti. Sembra che nessuno di questi presupposti sia vero e l'errore si trova altrove.

Entrambi i database sono memorizzati su una macchina VirtualBox che collego tramite port forwarding dall'host. Eseguo il programma sulla macchina host.

Entrambi i database sono solo a scopo di test e non hanno altre connessioni da gestire. Forse dovrò riscrivere il problema per aggirare questo problema, ma ho bisogno di inserimenti molto dispendiosi in termini di tempo altrove (in esecuzione approssimativamente per giorni) quindi sono molto preoccupato per alcuni limiti di tempo nascosti in psycopg2 o PostgreSQL.

+1

I problema potrebbe essere nella variabile work_mem nella configurazione. AFAIK questa variabile imposta la memoria massima consentita per una connessione. Controllare i registri ci dovrebbe essere una voce su cosa è sbagliato – Voooza

+0

Ma poi l'istruzione SELECT non avrebbe funzionato affatto, non è vero? Ma ho perso la connessione a 'outdb'. – WolfgangA

+0

Utilizzare 'COPY' o transazioni più grandi. Eseguendo solo 100 record all'interno di una singola transazione, ne ottieni circa 110.000 transazioni per completare l'intero lavoro. Una singola unità 7400rpm può gestire solo 120 commit al secondo (a meno che non si trovi a causa della cache, ciò renderebbe inaffidabile). Il tuo problema attuale sembra un problema di rete. –

risposta

4

Non conosco alcun timeout "nascosto" nella stessa postgresql. PostgreSQL ha statement_timeout, ma se lo premi dovresti ottenere uno ERROR: canceling statement due to statement timeout nel log del server (e registrerà anche l'istruzione annullata). Non posso parlare per psycopg2. Controllare definitivamente il log del server per tutto ciò che sembra rilevante.

Forse si tratta di un problema di rete? Una dichiarazione di lunga durata sarà una connessione TCP che rimane inattiva per un lungo periodo di tempo. Forse il tuo port forwardinging elimina le connessioni che sono inattive per più di 30 minuti? Forse le tue connessioni TCP non stanno usando keepalive. Postgresql ha alcune impostazioni per la messa a punto del TCP keepalive (tcp_keepalives_interval ecc.) E potrebbe anche essere necessario eseguire alcune configurazioni del kernel/rete per assicurarsi che siano effettivamente abilitate.

ad es. Ho appena provato a connettermi alla mia macchina qui e alle impostazioni predefinite da tcp_keepalives_interval a 7200, ovvero 2 ore. Se il tuo port forwarding viene interrotto dopo 30 minuti, questo default non lo farà. È possibile sovrascrivere l'impostazione utilizzata nella stringa di connessione del client (presupponendo che sia possibile spostare direttamente la stringa di conninfo) o impostare la variabile GUC nelle proprietà utente/database o postgresql.conf.

Vedi:

+0

Grazie mille per i tuoi link! – WolfgangA

0

Per inserire millons di righe, mi piacerebbe guardare attraverso il funzionario guide per compilazione di un db e considerare l'utilizzo di copy.

0

Ho un comando admin di django che aggiorna migliaia di migliaia di righe. Dopo un po 'di tempo, vedo lo stesso errore. Credo che l'utilizzo della memoria superi il limite. Non so come controllare manualmente la transazione nei comandi, però.

Problemi correlati