2009-06-07 39 views
7

que tiene un programa Java que se ejecuta un montón de consultas en una base de datos SQL Server. El primero de ellos, cuyas consultas en una vista arrojan unos 750k registros. Puedo ejecutar la consulta a través del estudio de administración del servidor sql, y obtengo resultados en aproximadamente 30 segundos. sin embargo, inicié el programa para correr anoche. cuando lo revisé esta mañana, esta consulta aún no había devuelto los resultados al programa Java, unas 15 horas después.funcionamiento lento de java

que tienen acceso a la base de datos para hacer casi cualquier cosa que quiera, pero realmente no estoy seguro de cómo empezar la depuración de esto. ¿Qué debe uno hacer para descubrir qué está causando una situación como esta? No soy un dba, y no estoy íntimamente familiarizado con el conjunto de herramientas del servidor sql, por lo que los detalles que me puede dar sobre cómo hacer lo que podría sugerir serían apreciados.

aquí está el código

stmt = connection.createStatement(); 
clientFeedRS = stmt.executeQuery(StringBuffer.toString()); 

EDIT1:

Bien, ha pasado un tiempo, y esto se desvió, pero este tema está de vuelta. Intenté actualizar desde el controlador jdbc v 1.2 a 2.0, pero estamos atascados en jdk 1.4, y v 2.0 requiere jdk 1.5, por lo que no es un iniciador. Ahora estoy viendo mis propiedades de cadena de conexión. Veo 2 que podrían ser útiles.

SelectMethod=cursor|direct 
responseBuffering=adaptive|full 

En la actualidad, con el problema de latencia, estoy funcionando con el cursor como el SelectMethod, y con el valor predeterminado para responseBuffering que está lleno. ¿Cambiar estas propiedades es probable que ayude? si es así, ¿cuál sería la configuración ideal? Estoy pensando, basado en lo que puedo encontrar en línea, que usar un método de selección directa y un buffer de respuesta adaptativa podría resolver mi problema. ¿Alguna idea?

Edit2:

Bueno, yo terminó cambiando estos dos parametros de cadena de conexión, utilizando el método de selección por defecto (directo) y especificando el responseBuffering como adaptativa. Esto termina trabajando mejor para mí y alivia los problemas de latencia que estaba viendo. Gracias por toda la ayuda.

+0

una publicación de su llamada a jdbc sería útil para averiguar qué, en todo caso, es incorrecto –

+0

¿Cuál es el programa de Java? Probablemente se requiera un fragmento de código de cómo está accediendo al DB.Además, ¿está SQL Server Studio limitando los resultados (por ejemplo, las primeras 1000 filas) que podrían sesgar los resultados? – cletus

+0

si estaba limitando los resultados a 1k filas, ¿cómo puedo estar seguro de que no? – shsteimer

Respuesta

4

Asegúrese de que su controlador JDBC esté configurado para usar una conexión directa y no una conexión basada en cusror. Puede publicar su URL de conexión JDBC si no está seguro.

Asegúrese de estar utilizando un conjunto de resultados de solo lectura, de solo lectura (este es el valor predeterminado si no lo está configurando).

Y asegúrese de estar utilizando controladores JDBC actualizados.

Si todo esto no funciona, entonces debe mirar el generador de perfiles sql y tratar de capturar la consulta sql, ya que el controlador jdbc ejecuta la instrucción y ejecutar esa declaración en el estudio de administración y ver si hay alguna diferencia .

Además, como está obteniendo demasiados datos, debe asegurarse de no tener retrasos en la recolección de memoria/basura en la JVM (aunque en este caso eso no explica la discrepancia de tiempo) .

+0

¿Por qué dices usar directo en lugar de cursor? ¿No se supone que la base ayuda con conjuntos de resultados grandes? – shsteimer

+0

@shsteimer, Accroding to Microsoft docs, Direct es más rápido. Solo debe usar los cursores si necesita el acceso fila por fila (o en JDBC, si necesita transacciones distribuidas en múltiples bases de datos, no tiene otra opción. – Yishai

0

Tirando de que muchos datos se van a requerir mucho tiempo. Probablemente deberías encontrar la manera de no requerir tantos datos en tu aplicación en un momento dado. Página los datos o use lazy loading por ejemplo. Sin más detalles sobre lo que intentas lograr, es difícil de decir.

+0

Estoy bien con un largo tiempo, incluso estoy de acuerdo con que tomar varios minutos, decenas de minutos está bien, pero las horas solo me parece que algo extraño está sucediendo. – shsteimer

+0

¿Cómo va tu memoria en la caja? –

0

El hecho de que es rápida cuando se ejecuta desde el estudio de gestión podría ser debido a un plan de consulta en caché de forma incorrecta y fuera de los índices de fecha (por ejemplo, debido a una gran importación o supresiones). ¿Regresa rápidamente todos los 750,000 registros en SSMS?

Trate de volver a generar los índices (o si eso llevaría demasiado tiempo, actualizar sus estadísticas); y quizás vaciar el caché del procedimiento (tenga cuidado si se trata de un sistema de producción ...): DBCC FREEPROCCACHE

+0

¿Puede quizás elaborar un poco más? Estoy luchando con un problema de rendimiento [similar] (http://stackoverflow.com/questions/26501791/microsoft-jdbc-4-0-driver-apparently-ignores-responsebuffering-adaptive) y aún no he encontrado una solución. – Drux

0

Para comenzar a depurar esto, sería bueno determinar si el área problemática está en la base de datos o en la aplicación. ¿Has intentado cambiar la consulta para que arroje un resultado mucho más pequeño? Si eso no retorna, le sugiero que apunte a la forma en que está accediendo al DB desde Java.

-1

¿Considera una cantidad similar de tiempo con SQLWB? Si la versión de Java es mucho más lenta, entonces verificaría un par de cosas:

  1. Debería obtener el mejor rendimiento con un ResultSet solo de reenvío, de solo lectura.
  2. Recuerdo que los controladores JDBC anteriores de MSFT eran lentos. Asegúrese de estar utilizando lo último-n-mejor. Creo que hay un SQL Server genérico uno y uno específicamente para SQL 2005.
3

Si la consulta es parametrizada puede ser un parámetro que falta o un parámetro que se establece con la función incorrecta, por ejemplo, setLong para cadena, etc. Intente ejecutar su consulta con todos los parámetros codificados en el cuerpo de la consulta sin ningún ? para ver si esto es un problema.

+0

Al menos tengo alguna pista para mi problema con esta respuesta. – vkrams

0

Presupuesto de las directrices de amortiguación adaptativa MS:

Evitar el uso de la propiedad de cadena de conexión SelectMethod = cursor para permitir la aplicación para procesar un gran conjunto de resultados. La función de almacenamiento en búfer adaptativo permite que las aplicaciones procesen conjuntos de resultados de solo lectura y de solo lectura muy grandes sin usar un cursor de servidor. Tenga en cuenta que cuando establece selectMethod = cursor, todos los conjuntos de resultados solo de lectura directa producidos por esa conexión se ven afectados. En otras palabras, si su aplicación procesa rutinariamente conjuntos de resultados cortos con algunas filas, la creación, lectura y cierre de un cursor de servidor para cada conjunto de resultados utilizará más recursos tanto del lado del cliente como del servidor que en el caso en que el método selectMethod no está establecido en cursor.

Y

Hay algunos casos en los que el uso de SelectMethod = cursor en lugar de responseBuffering = adaptación sería más beneficioso, tales como:

  • Si la aplicación procesa un sólo hacia adelante , el resultado de solo lectura se establece lentamente, como leer cada fila después de alguna entrada de usuario, utilizando selectMethod = cursor en lugar de responseBuffering = adaptive podría ayudar a reducir el uso de recursos por SQL Server.

  • Si su aplicación procesa dos o más conjuntos de resultados solo de reenvío al mismo tiempo en la misma conexión, usar selectMethod = cursor en lugar de responseBuffering = adaptive puede ayudar a reducir la memoria requerida por el controlador mientras procesa estos conjuntos de resultados.

En ambos casos, es necesario tener en cuenta la sobrecarga de crear, leer y cerrar los cursores de servidor.

Ver más: http://technet.microsoft.com/en-us/library/bb879937.aspx

7

Parece esto puede no haber aplicado a su situación particular, pero quería dar otra explicación posible para alguien en busca de este problema.

Acabo de tener un problema similar en el que una consulta ejecutada directamente en SQL Server tardó 1 minuto, mientras que la misma consulta tardó 5 minutos a través de un statemnent preparado en java. Lo rastreé hasta el hecho de que fue hecho como una declaración preparada.

Cuando ejecuta una consulta directamente en SQL Server, le proporciona una consulta no parametrizada, en la que conoce todos los criterios de búsqueda en el momento de la optimización. En mi caso, mis criterios de búsqueda incluían un rango de fechas, y el servidor SQL pudo verlo, decidir "ese rango de fechas es enorme, no usemos el índice de fecha" y luego eligió algo mucho mejor.

Cuando ejecuto la misma consulta a través de una declaración preparada para Java, en el momento en que SQL Server está optimizando la consulta, aún no le ha proporcionado ninguno de los valores de parámetro, por lo que debe adivinar a qué índice utilizar. En el caso de mi rango de fechas, si se optimiza para un rango pequeño y le doy un rango grande, funcionará más lento de lo que podría. Del mismo modo, si optimiza para un rango grande y le doy uno pequeño, de nuevo va a funcionar más lento de lo que podría.

Para demostrar que este era el problema, como experimento intenté darle consejos sobre qué optimizar para usar la opción "OPTIMIZAR PARA" de SQL Server. Cuando le dije que utilizara un pequeño rango de fechas, mi consulta java (que en realidad tenía un amplio rango de fechas) en realidad tomó el doble de tiempo que antes (10 minutos, en lugar de 5 minutos antes, y no 1 minuto en SQL Server) Cuando le dije mis fechas exactas para optimizar, el tiempo de ejecución fue idéntico entre la declaración preparada de Java.

Así que mi solución fue codificar las fechas exactas en la consulta. Esto funcionó para mí porque era solo una declaración única. El PreparedStatement no fue pensado para ser reutilizado, sino simplemente para parametrizar los valores para evitar la inyección de SQL. Como estas fechas venían de un objeto java.sql.Date, no tuve que preocuparme por los valores de fecha que contenían el código de inyección.

Sin embargo, para una declaración que DEBE ser reutilizada, la codificación de las fechas no funcionaría. Tal vez una mejor opción para eso sería crear múltiples declaraciones preparadas optimizadas para diferentes intervalos de fechas (una por día, una por una semana, una por un mes, una por un año y una por una década ... o quizás usted solo necesita 2 o 3 opciones ... No lo sé) y luego para cada consulta, ejecute la única declaración preparada cuyo rango de tiempo coincide mejor con el rango en la consulta real.

Por supuesto, esto solo funciona bien si los intervalos de fechas se distribuyen uniformemente. Si el 80% de sus registros fueron en el último año y el 20% se extendió en los últimos 10 años, entonces hacer el "tipo de consultas múltiples según el tamaño del rango" podría no ser el mejor. Tendría que optimizar sus consultas en función de rangos específicos o algo así. Tendría que averiguarlo a través de un error de prueba.

+0

Muchas gracias Esto resultó ser la causa de la lentitud en mi caso, y específicamente cuando mi declaración SQL preparada implicó una combinación de base de datos cruzada. Cuando no tenía una combinación de base de datos cruzada, una consulta muy similar con declaraciones preparadas no tenía el rendimiento problema –

+0

¡Gracias por esta idea! Tenía un SQL al que estaba conectando poco más de 300 valores, y veía tiempos de ejecución en mi programa de más de 100.000 ms. Pero cuando tomé ese mismo SQL y lo ejecuté en MSSQL Studio me pareció parecía que funcionaba instantáneamente. No tenía idea de por qué, aparte de algo extraño sucediendo en el propio controlador JDBC. Vi esta publicación, así que ahorcó la lógica para no usar todas esas variables, y ahora las consultas se ejecutan 500 veces más rápido !! Velocidades equivalentes a lo que estaba viendo fuera de mi programa. Increíble. – Dale

1

Sé que esta es una vieja pregunta, pero dado que es uno de los primeros resultados al buscar este problema, pensé que debería publicar lo que funcionó para mí. Tuve una consulta que tardó menos de 10 segundos cuando utilicé el controlador JDBC de SQL Server pero más de 4 minutos cuando uso jTDS. Probé todas las sugerencias mencionadas aquí y ninguna de ellas hizo ninguna diferencia. El único que funcionó es la adición de esto a la URL "; prepareSQL = 1"

Ver Here para más

13

tuve un problema similar, con una petición muy sencilla ocupando (SELECT desde donde =...) a 10 segundos para devolver una sola fila cuando se usa una conexión jdbc en Java, mientras toma solo 0.01s en sqlshell. El problema era el mismo si estaba usando el controlador MS SQL oficial o el controlador JTDS.

La solución fue la de configurar esta propiedad en la URL de JDBC: sendStringParametersAsUnicode = false

Ejemplo completo si está utilizando MS SQL piloto oficial: jdbc: sqlserver: // yourserver; instanceName = yourInstance; databaseName = yourDBName; sendStringParametersAsUnicode = false;

Instrucciones si utilizando diferentes controladores JDBC e infos más detallado sobre el problema aquí: http://emransharif.blogspot.fr/2011/07/performance-issues-with-jdbc-drivers.html

SQL Server diferencia sus tipos de datos que soportan Unicode de los que solo soportan ASCII. Por ejemplo, los tipos de datos de caracteres que admiten Unicode son nchar, nvarchar, longnvarchar donde sus contrapartes ASCII son char, varchar y longvarchar, respectivamente. De forma predeterminada, todos los controladores JDBC de Microsoft envían las cadenas en formato Unicode al SQL Server, independientemente de si el tipo de datos de la columna correspondiente definida en SQL Server admite Unicode o no. En el caso donde los tipos de datos de las columnas son compatibles con Unicode, todo es uniforme. Pero, en los casos en que los tipos de datos de las columnas no admiten Unicode, surgen serios problemas de rendimiento, especialmente durante las recuperaciones de datos. SQL Server intenta convertir tipos de datos no unicode en la tabla para unir tipos de datos antes de hacer la comparación. Además, si existe un índice en la columna no unicode, se ignorará. Esto llevaría finalmente a un escaneo completo de la tabla durante la captación de datos, lo que ralentizaría las consultas de búsqueda drásticamente.

En mi caso, tenía 30M + registros en la tabla desde la que estaba buscando. La duración para completar la solicitud pasó de más de 10 segundos a aproximadamente 0.01s después de aplicar la propiedad.

Espero que esto ayude a alguien!

+1

¡Muchas gracias! me ahorró horas de investigación! – rakpan

0

A veces puede deberse a la forma en que los parámetros son vinculantes para el objeto de consulta. Encontré que el siguiente código es muy lento al ejecutar desde el programa java.

Query query = em().createNativeQuery(queryString)      
       .setParameter("param", SomeEnum.DELETED.name()) 

Una vez que se quita el parámetro "borrado" y añadir directamente que "borrado" cadena a la consulta, se convirtió en súper rápido. Puede deberse a que SQL Server espera tener todos los parámetros vinculados para decidir el plan optimizado.

Cuestiones relacionadas