2009-01-07 17 views
6

Al desarrollar una nueva consulta en el trabajo, la escribí y la diseñé en SQL Query Analyzer. La consulta funcionaba muy bien sin ningún escaneo de tabla, pero cuando lo encapsulé dentro de un procedimiento almacenado, el rendimiento fue horrible. Cuando miré el plan de ejecución pude ver que SQL Server elegía un plan diferente que utilizaba un escaneo de tabla en lugar de un índice de búsqueda en TableB (me vi forzado a ofuscar los nombres de tabla y columna un poco pero ninguna lógica de consulta) ha cambiado).Plan de ejecución diferente al ejecutar instrucción directamente y desde el procedimiento almacenado

Aquí está la consulta

SELECT  
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day, 
    DATEPART(hh, TableA.Created) AS [Hour], 
    SUM(TableB.Quantity) AS Quantity, 
    SUM(TableB.Amount) AS Amount 
FROM 
    TableA 
    INNER JOIN TableB ON TableA.BID = TableB.ID 
WHERE  
    (TableA.ShopId = @ShopId) 
GROUP BY 
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)), 
    DATEPART(hh, TableA.Created) 
ORDER BY 
    DATEPART(hh, TableA.Created) 

Cuando ejecuto la consulta "en bruto" Me da la siguiente traza Estadísticas

 
Event Class   Duration CPU Reads Writes 
SQL:StmtCompleted 75  41  7  0 

Y cuando corro la consulta como un procedimiento almacenado utilizando el siguiente comando

DECLARE @ShopId int 
SELECT @ShopId = 1 
EXEC spStats_GetSalesStatsByHour @ShopId 

obtengo las siguientes estadísticas de trazas

 
Event Class   Duration CPU Reads Writes 
SQL:StmtCompleted 222  10  48  0 

también consigo el mismo resultado si almaceno la consulta en un nvarchar y ejecutarlo utilizando sp_executesql así (se comporta como el sproc)

DECLARE @SQL nvarchar(2000) 
SET @SQL = 'SELECT DATEADD(dd, ...' 
exec sp_executesql @SQL 

El procedimiento almacenado no contiene nada excepto para la declaración seleccionada arriba. ¿Qué podría hacer que el servidor SQL seleccione un plan de ejecución inferior solo porque la sentencia se ejecuta como un procedimiento almacenado?

Estamos actualmente en ejecución en SQL Server 2000

Respuesta

13

En general, esto tiene algo que ver con el descubrimiento de parámetros. Puede ser muy frustrante lidiar con eso. A veces puede ser resuelto por volver a compilar el procedimiento almacenado y, a veces incluso se puede utilizar una variable duplicado dentro del procedimiento almacenado de esta manera:

alter procedure p_myproc (@p1 int) as 
declare @p1_copy int; 
set @p1_copy = @p1; 

y luego usar @ p1_copy en la consulta. Parece ridículo, pero funciona.

comprobar mi reciente pregunta sobre el mismo tema:

Why does the SqlServer optimizer get so confused with parameters?

+1

Gracias hombre, que hizo el truco Felicitaciones por la rápida respuesta ridícula! –

-1

Sí - Yo había visto esto en 11g de Oracle DB también - corrió misma consulta rápida en 2 nodos de servidor SQL db en el indicador PERO cuando se llama desde el paquete literalmente colgó!

tuvo que borrar el grupo compartido para obtener un comportamiento idéntico: razón por la que se ejecutaba un trabajo/script que tenía una copia más antigua bloqueada en el caché/memoria de la biblioteca en un nodo con un plan de ejecución inferior.

Cuestiones relacionadas