2009-04-29 130 views
18

Tengo un procedimiento almacenado que se ejecuta mucho más rápido desde SQL Server Management Studio (2 segundos) que cuando se ejecuta con System.Data.SqlClient.SqlCommand (el tiempo de espera después de 2 minutos).alguna consulta SQL mucho más lento cuando se utiliza con SqlCommand?

¿Cuál podría ser el motivo de esto?


Detalles: en SQL Server Management Studio esta se ejecuta en 2 segundos (en la base de datos de producción):

EXEC sp_Stat 
    @DepartmentID = NULL 

En .NET/C# los siguientes tiempos de espera después de 2 minutos (en la base de datos de producción) :

string selectCommand = @" 
EXEC sp_Stat 
    @DepartmentID = NULL"; 
string connectionString = "server=***;database=***;user id=***;pwd=***"; 
using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    using (SqlCommand command = new SqlCommand(selectCommand, connection)) 
    { 
     connection.Open(); 
     using (SqlDataReader reader = command.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
      } 
     } 
    } 
} 

también probé con selectCommand = "sp_Stat", CommandType = StoredProcedure, y un SqlParameter, pero es el mismo resultado.

Y sin EXEC es el mismo resultado también.

En una base de datos de desarrollo casi vacía de datos, ambos casos finalizan en menos de 1 segundo. Por lo que está relacionado con que hay una gran cantidad de datos en la base de datos, pero parece ocurrir sólo de .NET ...


lo que Marc Gravell escribió sobre diferentes valores SET hace la diferencia en el caso presentado.

de SQL Server mostró que SQL Server Management Studio ejecuta los siguientes SET 's de que el Proveedor de .NET SQL Data cliente no:


SET ROWCOUNT 0 
SET TEXTSIZE 2147483647 
SET NOCOUNT OFF 
SET CONCAT_NULL_YIELDS_NULL ON 
SET ARITHABORT ON 
SET LOCK_TIMEOUT -1 
SET QUERY_GOVERNOR_COST_LIMIT 0 
SET DEADLOCK_PRIORITY NORMAL 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED 
SET ANSI_NULLS ON 
SET ANSI_NULL_DFLT_ON ON 
SET ANSI_PADDING ON 
SET ANSI_WARNINGS ON 
SET CURSOR_CLOSE_ON_COMMIT OFF 
SET IMPLICIT_TRANSACTIONS OFF 
SET QUOTED_IDENTIFIER ON 
SET NOEXEC, PARSEONLY, FMTONLY OFF 

Cuando he incluido estos, la misma consulta tomaron la misma cantidad de tiempo en SSMS y .NET. Y el responsable SET es ...

SET ARITHABORT ON 

¿Qué he aprendido? Tal vez de usar un generador de perfiles en vez de adivinar ...

(La solución en un principio parecía estar relacionado con descubrimiento de parámetros. Pero yo había mezclado algunas cosas ...)

+0

Una cosa más a tener en cuenta: si usted tiene una penalización de rendimiento con 'ARITHABORT OFF' se le puede unir dos tablas mediante una cadena y un campo numérico. En mi caso, la adición de un simple 'ISNUMERIC (string_field) = 1' cheque _antes_ la unión resuelto el problema :) – Loris

+0

Nunca hubiera considerado este - pregunta muy muy útil/respuesta! :) Solo tenemos una consulta SQL sin procesar que se ejecuta a través de Dapper y el mismo SET fue el culpable. Tenga en cuenta – Jedidja

+0

de establecer ARITHABORT ON en la capa de aplicación .. "agregando ARITHABORT SET ON para su procedimiento no es una solución. Parecerá a trabajar cuando lo pruebas. Pero eso es sólo porque a crear el procedimiento que obligó a una nueva compilación" Artículo completo aquí: http://www.sommarskog.se/query-plan-mysteries.html –

Respuesta

10

Otra cosa que puede ser importante es the SET options que están habilitados. Algunas de estas opciones cambian el plan de consulta lo suficiente como para cambiar el perfil. Algunos pueden tener un gran impacto si observa (por ejemplo) una columna calculada + persistente (y posiblemente indexada): si las opciones SET no son compatibles, se puede forzar a volver a calcular los valores, en lugar de usar el valor indexado - que puede cambiar una búsqueda de índice en un cálculo + escaneo de tabla.

intente utilizar el generador de perfiles para ver qué opciones están SET "en juego", y ver si el uso de esas opciones cambia las cosas.

Otro impacto es la cadena de conexión; por ejemplo, si habilita MARS que puede cambiar el comportamiento de maneras sutiles.

Finalmente, las transacciones (implícitas (TransactionScope) o explícitas) pueden tener un gran impacto , dependiendo del nivel de aislamiento.

+0

Gracias. Veré cómo examinar las opciones de SET.Supongo que podría estar relacionado con la diferencia, porque de lo contrario las consultas son idénticas ... –

+0

Hola Marc, He estado teniendo este problema durante años en un DB que estoy ejecutando, y la única solución ha sido SET ARITHABORT ENCENDIDO/OFF en el proceso almacenado Desafortunadamente sigue sucediendo y tengo que cambiar la opción ARITHABORT al opuesto de lo que era. ¿Conoces alguna forma de decirle a mi aplicación .NET que use las mismas opciones de SET que usará SSMS? –

+0

¿Es posible configurar ARITHABORT con Dapper, Marc? ¿Esto es algo que se establece en el nivel de conexión, en lugar del nivel de comando? ¿Es este un comando SQL que tengo que emitir cada vez que establezco una conexión? – crush

0

Hemos tenido un problema similar, en donde una consulta se completaría en 2 segundos en SSMS y tomaría más de 90 segundos cuando se llamara desde un cliente .NET (escribimos varias aplicaciones/sitios VB/C# para probarlo)

Sospechamos que el plan de consulta sería diferente y volvieron a escribir la consulta con un bucle explícito ("bucle interno unirse" y "con el índice") consejos. Esto resolvió el problema.

+0

¡Espero que haya examinado primero sus estadísticas e índices! ;) –

+0

Sí, tenemos un plan de mantenimiento semanal para estadísticas e índices (se ejecuta todos los domingos). Recreamos el procedimiento almacenado para eliminar cualquier plan de consulta en caché. – Andomar

5

Esto es casi seguro debido a un plan de consulta en caché "incorrecto". Esto ha aparecido en SO unas cuantas veces.

¿Tiene estadísticas actualizadas? ¿Un plan de mantenimiento de índice programado regularmente?

Se puede comprobar si se trata sin duda debido al plan de consulta en caché añadiendo esto a su definición del procedimiento almacenado:

CREATE PROCEDURE usp_MyProcedure WITH RECOMPILE... 

Esto volverá a índice de una base de datos completa (precaución si la base de datos es muy grande!):

exec sp_msforeachtable "dbcc dbreindex('?')" 

SO mensajes:

Big difference in execution time of stored proc between Managment Studio and TableAdapter.

Parameter Sniffing (or Spoofing) in SQL Server

optimize for unknown for SQL Server 2005?

Different Execution Plan for the same Stored Procedure

+0

Ejecuté exactamente las mismas consultas (EXEC sp_Stat @DepartmentID = NULL) una detrás de otra. Primero, el que tomó 2 segundos con SSMS. Luego (unos segundos más tarde) el que se agotó el tiempo de .NET. ¿Crees que todavía podría estar relacionado con un plan de consulta en caché incorrectamente? –

+0

eso o estadísticas no están actualizadas, o índices tienen que ser reconstruido (que actualiza las estadísticas en las respectivas columnas) –

+0

utilizo exactamente los mismos parámetros. Y la opción WITH RECOMPILE no cambia el resultado ... –

0

Tuve un problema similar y resulta que tener MultipleActiveResultSets = true en la cadena de conexión (que se supone tiene un impacto mínimo) hacía que extraer 1,5mil de registros a través de una conexión remota tomara 25 minutos en lugar de 2 minutos.

Cuestiones relacionadas