2009-10-01 19 views
8

Sto cercando di eseguire una query di PostgreSQL che restituisce un grande risultato:JDBC + PostgreSQL query di grandi dimensioni danno di memoria

connection.setAutoCommit(false); 
st = connection.createStatement(
    ResultSet.CONCUR_READ_ONLY, 
    ResultSet.TYPE_FORWARD_ONLY 
); 
st.setFetchSize(100); 
logMemory(); 
System.out.println("start query "); 
rs = st.executeQuery(queryString); 
System.out.println("done query "); 
logMemory(); 

ma questo utilizza un sacco di memoria:

Free memory; 4094347680 (= 3905 mb). 
start query 
done query 
Free memory; 2051038576 (= 1956 mb). 

(stampato con Runtime.getRuntime(). freeMemory())

Finora funziona, ma il database sarà molto più grande. Non ho mai bisogno dell'intero risultato in memoria; Ho solo bisogno di processare ogni riga, scrivere i risultati su disco e andare alla riga successiva.

So che "setFetchSize" è solo un suggerimento, ma lo troverei strano se postgresql/jdbc lo ignorasse, visto che esiste da anni.

Un modo per aggirare questo? La mia unica idea è quella di creare uno script batch che trasmetta il risultato della query su disco e quindi analizzare il file da Java ...

+0

Solo curioso, qual è la dimensione massima dell'heap con cui stai lavorando? O stai usando il default? –

+1

È -Xmx4096M -Xms4096M, è una macchina da 8 GB con vista. – kresjer

risposta

7

Ouch, questo è uno dei bug più fastidiosi con JDBC che ho visto. Si dovrebbe cambiare

st = connection.createStatement(
    ResultSet.CONCUR_READ_ONLY, 
    ResultSet.TYPE_FORWARD_ONLY 
); 

in

st = connection.createStatement(
    ResultSet.TYPE_FORWARD_ONLY, 
    ResultSet.CONCUR_READ_ONLY 
); 

Forse semplicemente

st = connection.createStatement(); 

funziona altrettanto bene (come hai incontrato gli altri criteri per un cursore).

+0

qual è il bug? è una vera perdita di memoria o qualcos'altro sta succedendo? Pensi che sia solo Postgres? – rogerdpack

+0

@rogerdpack OP ha modificato i parametri del metodo per 'createStatement'. Entrambi i parametri sono 'int'-s ma significa alcune cose diverse. Quindi non è un bug nell'implementazione JDBC. –

9

Here sono le linee guida per garantire che il set di risultati venga effettivamente recuperato con un cursore . Sembra che tu abbia colpito tutti quelli conosciuti nel tuo codice, ma non hai specificato l'istruzione, quindi potrebbe essere più teso insieme al punto e virgola (improbabile, dall'aspetto del tuo codice). Devi usare il protocollo V3 (versione 7.4 o successiva). Tutte queste cose si applicano al tuo caso?

+0

Sì, ho provato ad accendere/spegnere tutte le linee guida. La dichiarazione è semplicemente Selezionare hh.data, hh.customer_ID da dataTable hh unire cliente PH su hh.customer_ID = PH.customer_ID; ed è postgresql 8.3 e sto usando postgresql-8.3-603.jdbc4.jar. – kresjer

+0

Sono perplesso. Direi che il prossimo passo migliore è pubblicare post su gruppi che si concentrano su Postgresql. Ci sono probabilmente altre cose non ovvie che causano/possono forzare la connessione ad usare un cursore. Potrei aprire il codice sorgente JDBC (questa è la cosa bella dell'open source) e vedere cosa sta succedendo nel tuo scenario. – Yishai

+1

Grazie mille per la risposta. Stavo affrontando questo problema per tutto il giorno, finché non ho trovato un requisito per 'conn.setAutoCommit (false)' nella pagina che hai citato. – jutky

Problemi correlati