2009-10-01 15 views
8

Estoy tratando de ejecutar una consulta PostgreSQL, que devuelve un resultado grande:JDBC + amplia consulta PostgreSQL dan fuera de la 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(); 

pero esto consume mucha memoria:

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

(impreso con Runtime.getRuntime(). freeMemory())

Hasta ahora funciona, pero la base de datos va a ser mucho más grande. No necesito el resultado completo en la memoria; Solo necesito procesar cada fila, escribir los resultados en el disco y pasar a la siguiente fila.

Sé que 'setFetchSize' es solo una sugerencia, pero me resultaría extraño si postgresql/jdbc lo ignorara, ya que existe desde hace mucho tiempo.

¿Alguna forma de evitar esto? Mi única idea hasta ahora es hacer un script por lotes que transmita el resultado de la consulta al disco y luego analizar el archivo desde Java ...

+0

Simplemente curioso, ¿cuál es el tamaño máximo de almacenamiento dinámico con el que se está ejecutando? ¿O estás usando el valor predeterminado? –

+1

Es -Xmx4096M -Xms4096M, es una máquina de vista de 8GB. – kresjer

Respuesta

7

Ouch, este es uno de los errores más desagradables que he usado con JDBC. Debe cambiar

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

en

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

Tal vez simplemente

st = connection.createStatement(); 

funcionará tan bien (a medida que cumple los demás criterios para un cursor).

+0

¿cuál es el error? ¿Es una pérdida de memoria real o está sucediendo algo más? ¿Crees que es solo postgres? – rogerdpack

+0

@rogerdpack OP cambió los parámetros del método para 'createStatement'. Ambos parámetros son 'int'-s pero significan cosas diferentes. Entonces no hay ningún error en la implementación de JDBC. –

9

Here son las pautas para garantizar que el conjunto de resultados se recupera realmente con un cursor . Parece que acertaste con todas las conocidas en tu código, pero no has especificado la declaración, por lo que puede estar unida a puntos y comas (improbable, por el aspecto de tu código). Tienes que estar usando el protocolo V3 (versión 7.4 o posterior). ¿Se aplican todas estas cosas a su caso?

+0

Sí, he intentado activar/desactivar todas las pautas. La instrucción es simplemente Seleccione hh.data, hh.customer_ID de dataTable hh únete al cliente PH en hh.customer_ID = PH.customer_ID; y es postgresql 8.3 y estoy usando postgresql-8.3-603.jdbc4.jar. – kresjer

+0

Estoy perplejo. Yo diría que el siguiente mejor paso es publicar en grupos que se centren en Postgresql. Probablemente haya otras cosas no obvias que causen o puedan forzar a la conexión a usar un cursor. Me gustaría abrir el código fuente de JDBC (que es lo bueno de código abierto) y ver qué está sucediendo en su escenario. – Yishai

+1

Muchas gracias por la respuesta. Estuve luchando con este problema durante todo el día, hasta que encontré un requisito para 'conn.setAutoCommit (false)' en la página que citó. – jutky

Cuestiones relacionadas