none
SqlAdapter adapter.Fill(dataTable) muy lento RRS feed

  • Pregunta

  • Buenos días.

    Estoy realizando una apartado de estadísticas, y me he creado un procedimiento almacenado que me devuelve datos entre  2 fechas.

    Tengo lo siguiente:

                using (SqlConnection conn = new SqlConnection(connectionstring))
                {
                    conn.Open();
                    using (SqlCommand cmd = new SqlCommand("SPEstadisticasWebByFechas", conn))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                       
                        cmd.Parameters.AddWithValue("@fecha_desde", fechaDesde);
                        cmd.Parameters.AddWithValue("@fecha_hasta", fechaHasta);
    
                        using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
                        {
                            dt = new DataTable();
                            adapter.Fill(dt);
                        }
                    }
                }

    Resulta que al llegar al adapter.Fill(dt) se queda bloqueado y me lanza una excepción de tiempo de espera agotado.

    Si ejecuto el procedimiento almacenado, y me traigo todas las filas que tiene el tiempo máximo es de 10 segundos (22053 filas).

    Pero me lanza la excepción sin traerme ni siquiera la totalidad de todos los datos, he probado a ponerle llamar al storeprocedure mediante un DataReader y tampoco.

    ¿Por que se demora tanto en rellenar el dataTable?, ¿qué solución podría aplicar?

    Gracias.


    lunes, 23 de mayo de 2016 11:37

Respuestas

  • Prueba a arrancar una captura con el Profiler sobre el SQL Server, y luego ejecuta el código cliente. Examina la captura, a ver qué es lo que le ha enviado el programa (no vaya a ser que le esté llegando algo distinto a lo que ejecutas cuando pruebas el procedimiento directamente sobre el servidor).

    Mira también los resultados de la ejecución tal como te los captura el Profiler, a ver qué tiempos de CPU arroja y que volúmenes de entrada/salida, a ver si se nota alguna diferencia con las estadísticas de I/O que obtienes cuando lo ejecutas directamente en SSMS. Tal vez esto revele alguna inconsistencia que pueda dar alguna pista sobre qué puede estar pasando.

    Si todo ello es consistente y no se observa ninguna anomalía en el lado servidor, podríamos concluir que tal vez el problema esté en la parte de la asignación de memoria para los 22000 registros en el DataTable. En este caso, el problema no debería producirse si se usa un DataReader (salvo que en el bucle del DataReader se haga un conjunto de asignaciones de memoria equivalente al que hace el Fill).

    • Propuesto como respuesta José De AlvaModerator lunes, 23 de mayo de 2016 21:08
    • Votado como útil dudasc miércoles, 25 de mayo de 2016 6:19
    • Marcado como respuesta dudasc miércoles, 25 de mayo de 2016 6:45
    lunes, 23 de mayo de 2016 17:46
  • A ver si me aclaro, entonces si le pasas las fechas al procedimiento como argumentos, va lento, pero si escribes las fechas dentro del procedimiento y lo llamas sin argumentos, va rápido? Prueba a pedirle el Plan de Ejecución desde SSMS, tanto en un caso como en el otro, y compáralos. Sospecho que obtendrás dos planes diferentes, de los cuales uno utiliza los índices y otro hace un barrido de tabla. Puede ser un problema de "parameter sniffing" en que en optimizador de consultas no decide el plan óptimo al no tener fijos los valores de los parámetros. Si fuera ese el problema, podrías resolverlo añadiendo dentro de la Select un hint para forzarla a usar el índice. Pero eso ya sería un problema de SQL y no del código llamante en ASP.NET, así que llegados a ese punto si no se resuelve el problema convendría plantearlo en el foro de SQL Server, no sería ya una pregunta de ASP.NET.
    • Marcado como respuesta dudasc miércoles, 25 de mayo de 2016 6:45
    miércoles, 25 de mayo de 2016 5:08

Todas las respuestas

  • hola

    como es el vinculo entre el sitio web y el servidor de base de datos ? o estan ambos local en la misma pc

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    lunes, 23 de mayo de 2016 13:41
  • En producción el servidor de base de datos está en el mismo servidor que el sitio web, al igual que las pruebas que realizo en local, tengo SQLServer en local y hago las pruebas en local.

    lunes, 23 de mayo de 2016 16:32
  • Prueba a arrancar una captura con el Profiler sobre el SQL Server, y luego ejecuta el código cliente. Examina la captura, a ver qué es lo que le ha enviado el programa (no vaya a ser que le esté llegando algo distinto a lo que ejecutas cuando pruebas el procedimiento directamente sobre el servidor).

    Mira también los resultados de la ejecución tal como te los captura el Profiler, a ver qué tiempos de CPU arroja y que volúmenes de entrada/salida, a ver si se nota alguna diferencia con las estadísticas de I/O que obtienes cuando lo ejecutas directamente en SSMS. Tal vez esto revele alguna inconsistencia que pueda dar alguna pista sobre qué puede estar pasando.

    Si todo ello es consistente y no se observa ninguna anomalía en el lado servidor, podríamos concluir que tal vez el problema esté en la parte de la asignación de memoria para los 22000 registros en el DataTable. En este caso, el problema no debería producirse si se usa un DataReader (salvo que en el bucle del DataReader se haga un conjunto de asignaciones de memoria equivalente al que hace el Fill).

    • Propuesto como respuesta José De AlvaModerator lunes, 23 de mayo de 2016 21:08
    • Votado como útil dudasc miércoles, 25 de mayo de 2016 6:19
    • Marcado como respuesta dudasc miércoles, 25 de mayo de 2016 6:45
    lunes, 23 de mayo de 2016 17:46
  • OK Alberto, mañana intentaré realizar lo que me comentas, y con los resultados los comentaré aquí.

    Me informaré antes del SQL Server Profiler y si está para SQL Server Express que es el que tengo en local, y lo que comentas del SSMS. 

    Muchas gracias

    lunes, 23 de mayo de 2016 18:28
  • Ah, no, en la Express no funciona el Profiler. Si es para tu máquina de desarrollo, te recomiendo que te instales una edición Developer (antiguamente costaba 50 USD, creo que ahora es gratis).
    lunes, 23 de mayo de 2016 18:35
  • Buenas Alberto.

    He descargado el Express Profiler de: http://expressprofiler.codeplex.com/

    He ejecutado el SP desde la web y me aparece que realiza la llamada:
    exec SPEstadisticasWebByFechas @fecha_desde='2008-10-10 00:00:00',@fecha_hasta='2009-10-10 00:00:00'
    go

    Si me llevo eso al SQLExpress y lo ejecuto tarda >20 MINUTOS, cuando paro la consulta me pone que ha recuperado en 20minutos 223 filas, pero en cambio si Modifico el SP pongo las variables @fecha_desde y @fecha_hasta

    set @fecha_desde='2008-10-10 00:00:00'
    set @fecha_hasta='2009-10-10 00:00:00'

    Y ejecuto la select apenas tarda en devolverme 2 segundos 910filas.

    La cabecera de mi SP es así:

    USE [pruebas]
    GO
    
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[SPEstadisticasWebByFechas]
    (	 
    	@fecha_desde datetime,	
    	@fecha_hasta datetime
    )
    AS
        SET NOCOUNT OFF;
        
    
    SET @fecha_desde = CONVERT(DATETIME, CONVERT(varchar(11),@fecha_desde, 111 ) + ' 00:00:00', 111) 
    SET @fecha_hasta = CONVERT(DATETIME, CONVERT(varchar(11),@fecha_hasta, 111 ) + ' 23:59:59', 111)
    
    SELECT ...
    Al ejecutarlo mediante EXEC es cuando no devuelve los datos inmediatamente y se demora.

    martes, 24 de mayo de 2016 12:40
  • A ver si me aclaro, entonces si le pasas las fechas al procedimiento como argumentos, va lento, pero si escribes las fechas dentro del procedimiento y lo llamas sin argumentos, va rápido? Prueba a pedirle el Plan de Ejecución desde SSMS, tanto en un caso como en el otro, y compáralos. Sospecho que obtendrás dos planes diferentes, de los cuales uno utiliza los índices y otro hace un barrido de tabla. Puede ser un problema de "parameter sniffing" en que en optimizador de consultas no decide el plan óptimo al no tener fijos los valores de los parámetros. Si fuera ese el problema, podrías resolverlo añadiendo dentro de la Select un hint para forzarla a usar el índice. Pero eso ya sería un problema de SQL y no del código llamante en ASP.NET, así que llegados a ese punto si no se resuelve el problema convendría plantearlo en el foro de SQL Server, no sería ya una pregunta de ASP.NET.
    • Marcado como respuesta dudasc miércoles, 25 de mayo de 2016 6:45
    miércoles, 25 de mayo de 2016 5:08