2010-10-08 17 views
6

Estaba viendo una consulta SQL muy lenta (que se origina en una aplicación Java que utiliza Hibernate implementada en JBoss 5.1). Esta consulta en particular arrojó unos 10 000 registros, pero aún tardó 40 o más.¿Alguna solución para las ineficiencias de TNS de Oracle (muchos viajes de ida y vuelta, latencia) desde una aplicación Java?

Terminé olfateando el tráfico con la base de datos (wireshark tiene un disector para TNS) y encontré algo inesperado. Cuando los datos provenían del servidor, cada fila de resultados estaba en su propio paquete TNS. Además, cada paquete TNS fue reconocido por el cliente (es decir, el servidor de la aplicación) antes de que se enviara el siguiente desde la base de datos. Para los registros de 10K, hay 10K recorridos de ida y vuelta para obtener un paquete y reconocerlo. El impacto en el rendimiento es enorme.

Esto es terriblemente ineficiente. TCP permite paquetes más grandes y tiene una serie de mecanismos (ventanas deslizantes, ACK retrasados) para reducir la latencia y aumentar el rendimiento. Sin embargo, en este caso, es el protocolo TNS en la parte superior que agrega su propia negociación.

Si ejecuto la misma consulta desde el SQL Developer de Oracle, no veo este patrón. La consulta se completa en aproximadamente 1/10 del tiempo, sin miles de viajes redondos.

Versión corta: El protocolo de cable de Oracle (TNS) parece pasar datos en un paquete TNS por fila de resultados de consulta y requiere que cada paquete sea confirmado por el cliente antes de que el servidor envíe el siguiente.

He encontrado algo de información sobre esto [aquí] [1] (desplácese hacia abajo hasta la sección sobre 'Los parámetros SDU y TDU en el archivo tnsnames.ora').

Y, por tanto, mi pregunta: ¿es posible controlar el comportamiento del controlador de Oracle (estoy usando 10.2.0.4.0) para que el protocolo TNS sea más eficiente? De nuevo, esta es una aplicación J2EE bastante estándar implementada en JBoss.

¡Muchas gracias!

+0

Oye, gracias por la profundidad Pregunta con algunas sugerencias para personas que tienen situaciones similares. Votaron ... – TonyP

Respuesta

6

Tune los SDU y TDU parámetros en tnsnames.ora y listener.ora

Para establecer el tamaño del lote a 100 para la declaración actual.

((OracleStatement)stmt).setRowPrefetch (100); 

Nota:

Ajuste del tamaño de captación previa puede afectar el rendimiento de una aplicación. Aumentar el tamaño de captación previa será reducir el número de viajes de ida y vuelta necesarios para obtener todos los datos, pero aumentará el uso de memoria. Esto hará que dependa del número y tamaño de las columnas en la consulta y del número de filas que se espera que se devuelvan. Se también depende de la carga de la memoria y la CPU de la máquina cliente JDBC. El óptimo para una aplicación de cliente independiente será diferente de un servidor de aplicaciones muy cargado .La velocidad y la latencia de la conexión de red también deben ser consideredconnection también debe ser considerado

(de Oracle Database JDBC Developer's Guide and Reference)

disponibles propiedades de conexión here.

También eche un vistazo a Oracle UCP también.

+0

Gracias, después de la obtención previa de búsquedas en la fila de Google encontré lo siguiente: "JDBC estándar recibe el conjunto de resultados una fila a la vez, y cada fila requiere un viaje de ida y vuelta a la base de datos" en http://download.oracle.com/docs/cd/ B19306_01/java.102/b14355/oraperf.htm que explica lo que he visto. Hmm ... ¿es posible establecer el nivel de la fuente de datos? La lista de parámetros en http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html no contiene una configuración para la captación previa. – wishihadabettername

+1

Mientras tanto, encontré una propiedad del controlador (defaultRowPrefetch) en http://download.oracle.com/docs/cd/B19306_01/java.102/b14355/urls.htm#i1006362 – wishihadabettername

+0

¿Está utilizando UCP? http://www.oracle.com/technetwork/database/features/jdbc/index-091264.html – oluies

3

Trate de aumentar el tamaño de búsqueda para su objeto satement.

Creo que el defecto es 10, por lo que podría tratar de comenzar con 100.

 
Statement stmt = connection.createStatement(); 
stmt.setFetchSize(100); 
ResultSet rs = stmt.executeQuery("SELECT ..."); 
+0

Aumentar el tamaño de búsqueda mejoró las cosas al llenar los paquetes TCP de hecho. – wishihadabettername

Cuestiones relacionadas