2010-01-11 14 views
5

En nuestra base de datos de SQL Server 2005 (probado con Administración Estudio con DBCC FREEPROCCACHE y DBCC DROPCLEANBUFFERS), la siguiente declaración es rápido (~ 0,2 segundos de tiempo de compilación, ~ tiempo de 0,1 segundos de ejecución):Evitar el uso de ADO.NET sp_executesql

SELECT ... FROM ... WHERE a = 1 AND b = '' ... 

la siguiente declaración, sin embargo, es lento (~ 0,2 segundos de tiempo de compilación, 7-11s tiempo de ejecución):

exec sp_executesql N'SELECT ... FROM ... WHERE a = @a AND b = @b ...', N'@a int, @b nvarchar(4000), ...', @a=1, @b=N'', ... 

SQL Server elige un plan de ejecución diferente, aunque las consultas son iguales. Esto tiene sentido, ya que, en el primer caso, SQL Server tiene los valores reales de a, b y todos los demás parámetros disponibles y puede usar las estadísticas para crear un mejor plan. Aparentemente, el plan de consulta para los valores concretos de los parámetros es mucho mejor que el genérico y definitivamente supera cualquier beneficio de rendimiento de "caché de planes de consulta".

Ahora mi pregunta: ADO.NET siempre parece usar la segunda opción (sp_executesql) al ejecutar consultas parametrizadas, lo que suele ser tiene sentido (caché de plan de consulta, etc.). En nuestro caso, sin embargo, esto mata el rendimiento. Entonces, ¿hay alguna manera de cualquiera

  • fuerza de ADO.NET para usar algo diferente a sp_executesql (es decir, algo donde el analizador de consultas de SQL Server toma los valores reales de los parámetros en cuenta) O
  • fuerza de SQL Server para volver a recapitular el plan de consulta del SQL pasado a sp_executesqltomando los valores de los parámetros en la cuenta?

Y por favor, no me diga que tengo que volver a feo, viejo, peligroso sql = "WHERE b = " + quoteAndEscape(parameterB) ...

Poner el SQL en un procedimiento almacenado hace ninguna diferencia (lento, con y sin WITH RECOMPILE) . No publiqué el enunciado de SQL real ya que es bastante complejo (se une a varias tablas, incluidos los sub-SELECT y la agregación).

+0

convirtiéndolo en un procedimiento almacenado es tan lenta como la consulta ad hoc? Este es un comportamiento MUY extraño, así que debo preguntar: ¿estás seguro? –

+0

@Rubens: ¿por qué dices eso? ¿Qué ventaja de rendimiento ofrece un procedimiento almacenado sobre una consulta ad hoc en caché, compilada y parametrizada? –

+0

Sí, estoy seguro. ¿Por qué debería ser más rápido? El tiempo de compilación es insignificantemente pequeño (0.2s) en comparación con el tiempo de ejecución (7-11s). – Heinzi

Respuesta

4

Viejo lo sé, pero me acaba de encontrar buscando en Google o menos la misma frase exacta! Tuve exactamente el mismo problema (la consulta se ejecutó muy rápido en Management Studio usando parámetros, pero luego realmente lento a través de ADO.Net) y repliqué el problema ejecutando la consulta en Management Studio a través de "exec sp_execute". Los dos planes de ejecución fueron muy diferentes, incluso con Optimize para la sugerencia de consulta, por lo que lo que hice fue hacer una selección inicial de algunos de los datos en una tabla temporal. Eso pareció marcar la diferencia, y dado que usted dice que su consulta es compleja, también podría marcar la diferencia en su caso. No estoy muy seguro de cómo funcionó, pero pareció poner en marcha el plan de ejecución. línea incluso cuando se utiliza sp_execute.

+0

Eso es exactamente lo que terminamos haciendo: dividir la consulta en más pequeños usando tablas temporales ('# ...') para evitar que el optimizador de consultas elija un plan terriblemente malo. – Heinzi

2

Usted podría intentar el cual OPTIMIZE FOR query hint (cita):

Encarga el optimizador de consultas para utilizar un valor particular para una variable local cuando la consulta se compila y optimizado. El valor se usa solo durante la optimización de la consulta, y no durante la ejecución de la consulta. Optimizar para puede contrarrestar el parámetro de detección comportamiento del optimizador o puede ser utilizado al crear guías de plan

2

creo que el asunto tiene que ver con el uso del tipo de datos VARCHAR en la base de datos. SQL Server no parece usar el índice especificado si el parámetro where se declara como NVARCHAR.

Sin embargo, podría cambiar la columna de su base de datos a NVARCHAR (esto aumentaría el tamaño, por supuesto) y luego el rendimiento del índice probablemente mejore.

Actualmente estoy teniendo este problema con LINQ, y en realidad podría necesitar volver a usar procedimientos almacenados para evitarlo.

El asunto se explica en detalle en this Microsoft Connect discussion hilo

+0

Después de horas leyendo, olfateando problemas de parámetros, configurando el parámetro ARITHABORT, etc ... este es mi problema, no estaba estableciendo explícitamente el tipo de parámetros en mi consulta y estaban pasando como nvarchar, y tengo varchar en la base de datos. Gracias – Juan

0

Me gustaría mover la consulta a Procedimiento almacenado y luego en el comando especificar command.CommandType = CommandType.StoredProcedure.

Esto no crea sp_executesql y aumentar el rendimiento

Cuestiones relacionadas