2011-12-21 10 views
8

Tengo un servicio web, por lo que el controlador se llama varias veces al mismo tiempo todo el tiempo.bajo rendimiento con parámetro sql

En el interior Creo SqlConnection y SqlCommand. Tengo que ejecutar alrededor de 7 comandos diferentes. Diferentes comandos requieren varios parámetros, por lo que sólo se suman a la vez:

command.Parameters.Add(new SqlParameter("@UserID", userID)); 
command.Parameters.Add(new SqlParameter("@AppID", appID)); 
command.Parameters.Add(new SqlParameter("@SID", SIDInt)); 
command.Parameters.Add(new SqlParameter("@Day", timestamp.Date)); 
command.Parameters.Add(new SqlParameter("@TS", timestamp)); 

A continuación, durante la ejecución acabo de cambiar CommandText prorerty y luego llaman ExecuteNonQuery(); o ExecuteScalar();

Y me enfrento el problema de rendimiento. Por ejemplo pequeños debuggin y perfilado espectáculos, esta orden

command.CommandText = "SELECT LastShowTS FROM LogForAllTime WHERE UserID = @UserID"; 

toma alrededor de 50 ms en normalito. Si lo cambio a:

command.CommandText = "SELECT LastShowTS FROM LogForAllTime WHERE UserID = '" + userID.Replace("\'", "") + "'"; 

¡entonces solo se necesitan 1ms en avarage!

No puedo conseguir una pista sobre dónde investigar el problema.

+1

¿Puede indicar: cuál es el tipo definido de 'userID' en C#, y cuál es el tipo definido de la columna' UserID' en la base de datos? –

+0

¿Estás seguro de que este es tu cuello de botella de rendimiento? ¿Has perfilado todo? – asawyer

+0

ID de usuario es una cadena, en DB es varchar (20) y es un PK –

Respuesta

13

Parece que ha guardado en caché un plan de consulta para un valor atípico de @UserID (uno de los primeros) y está reutilizando un plan deficiente para consultas posteriores. Esto no es un problema en el segundo caso, ya que cada uno tiene un plan separado. Sospecho que sólo tiene que añadir:

OPTION (OPTIMIZE FOR UNKNOWN) 

a la consulta, lo que hará que sea menos agudo de reutilización de unos planes a ciegas.


teoría alternativa:

Es posible que tenga una falta de correspondencia entre el tipo de userID (en el C#) y el tipo de UserID (en la base de datos). Esto podría ser tan simple como Unicode vs ANSI, o podría ser int vs varchar[n], etc. En caso de duda, sea muy específico al configurar el parámetro, para agregarlo con el subtipo y tamaño correctos.

Aclaración

De hecho, parece que el problema aquí es la diferencia entre un C# string (Unicode) y la base de datos que es varchar(n) (ANSI). Por lo tanto, el SqlParameter debe agregarse explícitamente como tal (DbType.AnsiString).

+0

¿Realmente marcaría la diferencia para una cláusula 'WHERE' tan simple? – SLaks

+0

@SLaks si los datos son desiguales, sí; Imagínese: la primera consulta se ejecuta para un usuario de muestra sin datos (o muy pocos): el optimizador de consultas usa las estadísticas y decide un plan de consulta optimizado para pequeñas cantidades de filas. Esto luego explota enormemente cuando se enfrentan con 200k filas. He visto casos similares, absolutamente. Sin embargo, la única manera de averiguarlo es probarlo con o sin la pista; p –

+0

Bueno, esta es una característica interesante que seguramente investigaré con más detalle. El buen enlace está aquí http://blogs.msdn.com/b/sqlprogrammability/archive/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature.aspx So Lo intenté: SELECCIONE LastShowTS FROM LogForAllTime DONDE UserID = @UserID opción (OPTIMIZE FOR (@UserID UNKNOWN)) Sin efecto ... –

0

Está enviando siete veces más datos al servidor, por lo que será más lento.

Además, si sus cadenas userID tienen longitudes diferentes, establecer una longitud explícita en el parámetro SQL le permitirá reutilizar mejor la consulta.

+0

Eso no computa; esto solo se aplicaría si los parámetros fueran enormes y los problemas de ancho de banda fueran el cuello de botella; Dudo mucho que este sea el caso aquí. El tiempo para enviar unos pocos parámetros básicos es trivial, y ampliamente superado por la latencia (en lugar del ancho de banda) en la mayoría de los casos. –

+0

@MarcGravell: ¿Estás dirigiendo mi primer párrafo o mi segundo? – SLaks

+0

Primera línea: no esperaría que eso represente un salto de 50 ms. Tal vez una desviación de 0,1 ms (suponiendo que no hay valores enormes). –