2011-04-05 23 views
7

Todo es relativo, por supuesto, pero en comparación con simplemente ejecutar el mismo SQL utilizando el administrador de consultas, hay una gran diferencia.LINQ llamando a un procedimiento almacenado es lento

He utilizado el generador de perfiles para ver qué enunciados SQL ejecuta la base de datos cuando LINQ llama a un procedimiento almacenado. El resultado se devuelve en aproximadamente 1400 ms, si copio/pego el SQL y ejecuto exactamente el mismo SQL a través del administrador de consultas, el resultado se devuelve en 2 ms. Esto me hace preguntarme si hay algo que deba hacer. ¿Alguien aquí ha tenido experiencias similares?

El siguiente es el SQL envía desde LINQ:

declare @p26 int 
set @p26=0 
exec sp_executesql N'EXEC @RETURN_VALUE = [dbo].[TapeInfo_Get] @TapeFlag_IsDigitized = @p0, @TapeFlag_ChosenSingleTape = @p1, @TapeFlag_ChosenHierarchy = @p2, @TapeFlag_ChosenForced = @p3, @TapeFlag_ExcludedHierarchy = @p4, @TapeFlag_ExcludedARKBNR = @p5, @TapeFlag_ExcludedForced = @p6, @TapeFlag_ExcludedFilmRoll = @p7, @TapeFlag_ExcludedDVCPRO = @p8, @TapeFlag_ExcludedVHS = @p9, @TapeFlag_ExcludedType = @p10, @TapeFlag_NoticeBNR = @p11, @TapeFlag_NoticeMultiplePNR = @p12, @TapeFlag_NoticeType = @p13, @ProductionFlag_ExcudedDate = @p14, @ProductionFlag_NoticeMultipleTape = @p15, @ProductionFlag_NoticeFilm1C = @p16, @ProductionFlag_NoticeFilmBetaDigial = @p17, @ProductionFlag_ExcludedForeignProd = @p18, @Query = @p19, @PageIndex = @p20, @PageSize = @p21, @ReturnCount = @p22',N'@p0 bit,@p1 bit,@p2 bit,@p3 bit,@p4 bit,@p5 bit,@p6 bit,@p7 bit,@p8 bit,@p9 bit,@p10 bit,@p11 bit,@p12 bit,@p13 bit,@p14 bit,@p15 bit,@p16 bit,@p17 bit,@p18 bit,@p19 varchar(8000),@p20 int,@p21 int,@p22 bit,@RETURN_VALUE int output',@p0=0,@p1=1,@p2=1,@p3=1,@p4=0,@p5=0,@p6=0,@p7=0,@p8=0,@p9=0,@p10=0,@p11=0,@p12=0,@p13=0,@p14=0,@p15=0,@p16=0,@p17=0,@p18=0,@p19=NULL,@p20=0,@p21=10,@p22=0,@[email protected] output 
select @p26 

El código .Net C# es simplemente:

using(BRSDataContext dc = new BRSDataContext()) 
{ 
    dc.TapeInfo_Get(false, false, false, false, false, false, false, false, false, false, false, null, true, null, false, null, null, null, false, query, startRowIndex, count, false) 
} 

¿Hay algo que me falta? ¿Alguna idea de lo que puede influenciar el rendimiento tan dramáticamente? La base de datos (MSSQL 2008) y el servidor web que aloja el sitio asp.net que ejecuta el LINQ, están ubicados en la misma red y ambos ejecutan Windows Server 2008 std 32bit.

Gracias por la ayuda.

SOLUCIÓN:

SET ARITHABORT ON; 

así que no era un problema LINQ, pero más de una cuestión general de SQL Server.

+2

¿Cuál ejecutó primero? SSMS o la aplicación? ¿Puede generar repetidamente los mismos resultados de rendimiento al alternar entre los dos métodos de consulta? ¿Dónde está exactamente recibiendo las métricas que citó? –

+0

@Pete M, gracias por responder, primero llamé a través de LINQ, y copié el SQL en el administrador de consultas y lo ejecuté. Pero el resultado es bastante lento desde LINQ, incluso después de la primera llamada. Las medidas provienen del generador de perfiles, que se envía con el servidor SQL 2008. –

+0

Bummer, esperaba que fuera un problema de plan de ejecución ... Para que quede claro, ¿está viendo el tiempo de ejecución de 1400ms completamente en SQL Server? Como en, sin incluir transporte/presentación/otro? ¿Tienes LINQPad? Intentaré hacer referencia a su DataContext y ejecutar la consulta fuera del contexto de su aplicación y ver si obtiene los mismos resultados. Es realmente extraño ver ese tipo de diferencia completamente del lado del servidor, y consistentemente sobre múltiples aciertos, en un procedimiento almacenado no menos ... –

Respuesta

8

Establecer arithabort en; es solo para probarlo. Hay varias formas recomendadas para solucionar este problema. Una es agregar "con recompilación" al procedimiento almacenado. Pero por lo general solucionarlo por no usar los parámetros de entrada directamente

ejemplo:

create stored procedure foo(@ParamUserId int) 
as 
    declare @UserId int 
    set @UserId = @ParamUserId 

    select * from Users where UserId = @UserId 

O algo por el estilo.

Aquí es un buen artículo sobre el asunto http://www.simple-talk.com/sql/t-sql-programming/parameter-sniffing/

+0

Muchas gracias, muy útil. –

+1

Me alegro de ser de ayuda. Recuerdo que me rasqué la cabeza en este durante un día completo. Hubiera sido bueno saber de stackoverflow en ese entonces :) – ingo

+0

Excelente enlace a alguna investigación exhaustiva sobre el problema, pero hay tanto allí que necesitas A) al menos una hora para leerlo y digerirlo o B) 15 o 20 minutos para echarle un vistazo y tratar de encontrar la pieza que te ayude a solucionar tu problema. Fui por el último enfoque, pero el problema se repitió incluso después de ejecutar sp_recompile (que el autor del enlace anterior dice que será el caso probable). En mi caso, lo que finalmente solucionó mi problema fue cambiar los parámetros de fecha y hora que estaba pasando a mi sproc para los parámetros varchar (y luego los convertí a datetime dentro del sproc). – Jagd

2

Aquí está el C# para LINQ configurar arithabort sucesivamente;

System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(myConnectionString); 
System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand("set arithabort on;", conn); 
command.Connection.Open(); 
command.ExecuteNonQuery(); 
CMyDataContext myDataContext = new CMyDataContext(conn); 
Cuestiones relacionadas