2009-09-23 12 views
8

Sto utilizzando il seguente codiceJava JDBC ignora setFetchSize?

st = connection.createStatement(
      ResultSet.CONCUR_READ_ONLY, 
      ResultSet.FETCH_FORWARD, 
      ResultSet.TYPE_FORWARD_ONLY 
      ); 
st.setFetchSize(1000); 
System.out.println("start query "); 
rs = st.executeQuery(queryString); 
System.out.println("done query"); 

La query restituire un sacco di (800k) righe e prendere un grande tempo (~ 2 m) tra la stampa "start query" e "interrogazione fatto". Quando inserisco manualmente un "limite 10000" nella mia query non c'è tempo tra "start" e "done". Elaborare i risultati richiede tempo quindi immagino che nel complesso sia più veloce se recupera solo le righe da 1k dal database, le elabora e quando sta esaurendo le righe ne può ottenere di nuove in background.

Il ResultsSet.CONCUR_READ_ONLY ecc. Dove la mia ultima ipotesi; mi sto perdendo qualcosa?

(si tratta di un server PostgreSQL 8.3)

+0

setFetchSize in realtà funziona bene con il driver PostgreSQL, semplicemente fa un molto cosa diversa da come ti aspetti che faccia. Vedi la mia risposta. – Henning

+0

Vedere anche https://stackoverflow.com/a/47517489/32453 – rogerdpack

risposta

2

Questo dipenderà dal vostro driver. Dalla documentazione:

Dà il driver JDBC un suggerimento per quanto riguarda il numero di righe che dovrebbero essere recuperati dal database quando più righe sono necessario. Il numero di righe specificato riguarda solo i set di risultati creati utilizzando questa istruzione. Se il valore specificato è zero, il suggerimento viene ignorato. Il valore predefinito è zero.

Nota che si dice "un suggerimento" - vorrei prendere che a significare che un pilota può ignorare il suggerimento, se vuole davvero ... e suona come questo è ciò che sta accadendo.

+0

Sì, l'ho letto ma non potevo credere che JDBC + postgreSQL avrebbe ignorato questo, è in giro da secoli. – kresjer

+0

@kresjer: Its postgresql quindi è necessario avere accesso all'origine per i driver DB e JDBC. Potresti usarlo per capire cosa sta succedendo ... –

+0

NB che postgres (se l'autocommit è disattivato, quindi la dimensione del recupero funziona) l'impostazione della dimensione del recupero su 0 apparentemente lo rende cache di "tutto" per impostazione predefinita (suppongo che sia come interpretano "ignorando" un suggerimento) con oracle il default è 10 apparentemente http://docs.oracle.com/cd/A97335_02/apps.102/a83724/resltse5.htm – rogerdpack

20

Provare ad accenderlo auto-commit off:

// make sure autocommit is off 
connection.setAutoCommit(false); 

st = connection.createStatement(); 
st.setFetchSize(1000); 
System.out.println("start query "); 
rs = st.executeQuery(queryString); 
System.out.println("done query"); 

Reference

+1

Esattamente. setFetchSize non funziona in modalità autoCommit con il driver JDBC PostgresSQL. –

+1

Vale la pena notare che probabilmente è necessario riattivare l'autocommit prima di chiudere la connessione, se si utilizza il pool di connessioni e altre parti dell'app si basano su autocommit. Altrimenti potresti finire con la perdita casuale dei dati se non ti impegni esplicitamente. –

+1

Ulteriori dettagli su questa restrizione JDBC PostgreSQL sono disponibili all'indirizzo http://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor. – Alex

3

Le due query fare cose completamente diverse.

utilizzando la clausola LIMIT limita la dimensione del set di risultati a 10000, mentre l'impostazione della dimensioni di raccolta non lo fa, dà invece un suggerimento per il conducente dire quante righe per andare a prendere in un momento in quando iterazione attraverso il set di risultati - che include tutte le 800k righe.

Quindi, quando si utilizza setFetchSize, il database crea il set completo di risultati, ecco perché ci vuole così tanto tempo.

Edit per chiarezza: Impostazione della dimensione di recupero non fa nulla a meno di eseguire iterazioni attraverso il risultato (vedi il commento di Jon), ma la creazione di un risultato molto più piccolo impostato con LIMIT fa una grande differenza.

+0

Ma lui * non sta * iterando attraverso il set di risultati. L'idea è che * mentre * si scorre il set di risultati, idealmente si dovrebbero recuperare 1000 risultati sulla rete, quindi è possibile elaborarli, e quando si arriva al 1001st si recupereranno i successivi 1000 ecc. –

+0

Ovviamente. La differenza di velocità è dovuta a diverse dimensioni dei set di risultati, 10000 vs 800000. – Henning

2

ho notato che l'utilizzo delle API è diverso da quello espresso da Javadoc:

Prova a passare i parametri in questo ordine

ResultSet.TYPE_FORWARD_ONLY, 
    ResultSet.CONCUR_READ_ONLY, 
    ResultSet.FETCH_FORWARD 
+1

Questi 3 tasti, insieme all'impostazione conn.setAutoCommit (false) ha fatto il trucco per me – Peter

Problemi correlati