Plan de ejecución diferente cuando se ejecuta la instrucción directamente y desde el procedimiento almacenado

StackOverflow https://stackoverflow.com/questions/421275

Pregunta

Mientras desarrollaba una nueva consulta en el trabajo, la escribí y la perfilé en el Analizador de consultas SQL. La consulta se estaba desempeñando realmente bien sin ningún tipo de escaneo de tablas, pero cuando lo encapsulé dentro de un procedimiento almacenado, el desempeño fue horrible. Cuando miré el plan de ejecución, pude ver que SQL Server eligió un plan diferente que usaba un escaneo de tabla en lugar de una búsqueda de índice en TableB (me he visto obligado a ofuscar un poco los nombres de tabla y columna, pero ninguna de las lógicas de consulta). ha cambiado).

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 " Obtengo las siguientes estadísticas de seguimiento

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

Y cuando ejecuto la consulta como un proceso almacenado con el siguiente comando

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

Obtengo las siguientes estadísticas de seguimiento

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

También obtengo el mismo resultado si almaceno la consulta en un nvarchar y la ejecuto usando sp_executesql de esta manera (funciona como el sproc)

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

El procedimiento almacenado no contiene nada, excepto la instrucción de selección anterior. ¿Qué haría que el servidor SQL escoja un plan de ejecución inferior solo porque la instrucción se ejecuta como un procedimiento almacenado?

Actualmente estamos ejecutando en SQL Server 2000

¿Fue útil?

Solución

Esto generalmente tiene algo que ver con la detección de parámetros. Puede ser muy frustrante tratar con ellos. Algunas veces se puede resolver al compilar el procedimiento almacenado, y algunas veces incluso se puede usar una variable duplicada dentro del procedimiento almacenado de esta manera:

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

Y luego use @ p1_copy en la consulta. Parece ridículo pero funciona.

Revise mi pregunta reciente sobre el mismo tema:

¿Por qué el optimizador SqlServer está tan confundido con parámetros?

Otros consejos

Sí: también había visto esto en Oracle DB 11g - ¡la misma consulta se ejecutó rápidamente en 2 nodos del servidor db en el indicador SQL PERO cuando se llamó desde el paquete que literalmente se colgó!

tuvo que borrar el grupo compartido para obtener un comportamiento idéntico: la razón era que se estaba ejecutando un trabajo / script que tenía una copia anterior bloqueada en la memoria caché / memoria de la biblioteca en un nodo con un plan de ejecución inferior.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top