2009-09-23 17 views
8

estoy usando el siguiente códigoJava 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 consulta devolverá un montón de (800k) filas y tomar un tiempo más grande (~ 2 m) entre la impresión "iniciar consultas" y "consulta hecho". Cuando coloco manualmente un "límite 10000" en mi consulta, no hay tiempo entre "inicio" y "hecho". Procesar los resultados lleva tiempo, así que supongo que en general es más rápido si solo obtiene 1k filas de la base de datos, las procesa y cuando se está quedando sin filas puede obtener nuevas en segundo plano.

ResultSet.CONCUR_READ_ONLY, etc. donde fue mi última suposición; ¿Me estoy perdiendo de algo?

(es un servidor de PostgreSQL 8.3)

+0

setFetchSize funciona realmente bien con el conductor de PostgreSQL, que sólo hace un muy cosa diferente de lo que espera que haga. Ver mi respuesta – Henning

+0

Ver también https://stackoverflow.com/a/47517489/32453 – rogerdpack

Respuesta

2

Esto dependerá de su conductor. A partir de los documentos:

da al conductor JDBC una pista sobre el número de filas que deben captarse de la base de datos cuando existen más filas necesario. El número de filas especificado afecta solo a los conjuntos de resultados creados con esta declaración. Si el valor especificado es cero, la sugerencia se ignora. El valor predeterminado es cero.

Tenga en cuenta que dice "una pista" - Yo diría que un conductor puede ignorar la pista si realmente quiere ... y parece que eso es lo que está sucediendo.

+0

Sí, lo leí pero no podía creer que JDBC + postgreSQL ignoraría eso, existe desde hace siglos. – kresjer

+0

@kresjer: es postgresql, por lo que debe tener acceso a la fuente de los controladores DB y JDBC. Podrías usarlo para descubrir qué está pasando realmente ... –

+0

NB que postgres (si la confirmación automática está desactivada para que el tamaño de búsqueda funcione) configurando el tamaño de búsqueda en 0 aparentemente hace que cache "todo" por defecto (supongo que es cómo interpretan "ignorar" una pista) con Oracle el valor predeterminado es 10 aparentemente http://docs.oracle.com/cd/A97335_02/apps.102/a83724/resltse5.htm – rogerdpack

20

Intente encenderla auto-commit apagado:

// 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

Exactamente. setFetchSize no funciona en el modo autoCommit con el controlador PostgresSQL JDBC. –

+1

Vale la pena señalar que probablemente deba volver a activar la confirmación automática antes de cerrar la conexión, si está utilizando la agrupación de conexiones, y otras partes de la aplicación confían en el compromiso automático. De lo contrario, puede terminar perdiendo datos al azar cuando no se compromete explícitamente. –

+1

Se pueden encontrar más detalles sobre esta restricción PostgreSQL JDBC en http://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor. – Alex

3

Las dos consultas hacen cosas completamente diferentes.

El uso de la cláusula de LIMIT limita el tamaño del conjunto de resultados a 10.000, mientras que el establecimiento de la zona de alcance tamaño no lo hace, en cambio da una pista al conductor diciendo cuántas filas hay que seleccionar a la vez cuando se itera a través del conjunto de resultados - que incluye todas las 800k filas.

Por lo tanto, al usar setFetchSize, la base de datos crea el conjunto de resultados completo, es por eso que lleva tanto tiempo.

Editar para mayor claridad: Ajuste del tamaño de recuperación no hace nada menos que una iteración en el resultado (ver el comentario de Jon), pero la creación de un resultado mucho más pequeño establecido a través LÍMITE hace una gran diferencia.

+0

Pero él * no está * iterando a través del conjunto de resultados. La idea es que * mientras * iteras a través del conjunto de resultados, idealmente debería obtener 1000 resultados a través de la red, luego puedes procesarlos, y cuando llegues al 1001 obtendrás los siguientes 1000, etc. –

+0

Por supuesto. La diferencia de velocidad se debe a los diferentes tamaños de los conjuntos de resultados, 10000 frente a 800000. – Henning

2

me di cuenta de que el uso de la API es diferente de lo expresado por Javadoc:

Trate de pasar parámetros en este orden

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

Estas 3 claves, junto con la configuración de conn.setAutoCommit (falso) me funcionaron – Peter