2010-10-22 30 views
31

Estoy haciendo algunas pruebas con el generador de perfiles SQL 2005.La consulta se ejecuta rápidamente, pero se ejecuta lentamente en el procedimiento almacenado

Tengo un procedimiento almacenado que simplemente ejecuta una consulta SQL.

Cuando ejecuto el procedimiento almacenado, se necesita mucho tiempo y realiza 800.000 lecturas de disco.

Cuando ejecuto la misma consulta separada al procedimiento almacenado, lo hace 14.000 lecturas de disco.

He descubierto que si corro la misma consulta con la opción (recompilación), se necesita 800.000 lecturas de disco.

partir de esto, hago la suposición (posiblemente errónea) de que el procedimiento almacenado se recompilando cada vez, y que está causando el problema.

¿Alguien puede arrojar algo de luz sobre esto?

He establecido ARITHABORT ON. (Esto resolvió un problema similar en stackoverflow, pero no resolvió el mío)

Aquí es todo el procedimiento almacenado:

CREATE PROCEDURE [dbo].[GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED] 
@Contract_ID int, 
@dt_From smalldatetime, 
@dt_To smalldatetime, 
@Last_Run_Date datetime 
AS 
BEGIN 
DECLARE @rv int 


SELECT @rv = (CASE WHEN EXISTS 
(
    select * from 
    view_contract_version_last_volume_update 
    inner join contract_version 
    on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id 
    where [email protected]_ID 
    and volume_date >= @dt_From 
    and volume_date < @dt_To 
    and last_write_date > @Last_Run_Date 
) 
THEN 1 else 0 end) 

-- Note that we are RETURNING a value rather than SELECTING it. 
-- This means we can invoke this function from other stored procedures 
return @rv 
END 

Aquí es un script corro que demuestra el problema:

DECLARE 
@Contract_ID INT, 
@dt_From smalldatetime, 
@dt_To smalldatetime, 
@Last_Run_Date datetime, 
    @rv int 


SET @Contract_ID=38 
SET @dt_From='2010-09-01' 
SET @dt_To='2010-10-01' 
SET @Last_Run_Date='2010-10-08 10:59:59:070' 


-- This takes over fifteen seconds 
exec GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED @[email protected]_ID,@[email protected]_From,@[email protected]_To,@[email protected]_Run_Date 

-- This takes less than one second! 
SELECT @rv = (CASE WHEN EXISTS 
(
select * from 
view_contract_version_last_volume_update 
inner join contract_version 
on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id 
where [email protected]_ID 
and volume_date >= @dt_From 
and volume_date < @dt_To 
and last_write_date > @Last_Run_Date 
) 
THEN 1 else 0 end) 


-- With recompile option. Takes 15 seconds again! 
SELECT @rv = (CASE WHEN EXISTS 
(
select * from 
view_contract_version_last_volume_update 
inner join contract_version 
on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id 
where [email protected]_ID 
and volume_date >= @dt_From 
and volume_date < @dt_To 
and last_write_date > @Last_Run_Date 
) 
THEN 1 else 0 end) OPTION(recompile) 
+0

¿Cuál es la diferencia entre los dos "Planes de ejecución de consultas reales"? – Andomar

Respuesta

61

OK, hemos tenido problemas similares a este antes.

que no hemos resuelto esto, fue por lo que los parámetros locales dentro de la SP, de tal manera que

DECLARE @LOCAL_Contract_ID int, 
     @LOCAL_dt_From smalldatetime, 
     @LOCAL_dt_To smalldatetime, 
     @LOCAL_Last_Run_Date datetime 

SELECT @LOCAL_Contract_ID = @Contract_ID, 
     @LOCAL_dt_From = @dt_From, 
     @LOCAL_dt_To = @dt_To, 
     @LOCAL_Last_Run_Date = @Last_Run_Date 

, utilizamos los parámetros locales dentro de la SP en lugar de los parámetros que se aprobó en.

Esto generalmente solucionó el problema para nosotros.

Creemos que esto es debido al descubrimiento de parámetros, pero no tienen ninguna prueba, lo siento ... X)

EDIT:

Tenga una mirada en Different Approaches to Correct SQL Server Parameter Sniffing para algunos ejemplos interesantes, explicaciones y correcciones.

+3

Y ahora el procedimiento almacenado va tan rápido que tiene 0 duración en el generador de perfiles. Increíble. ¿Debo preocuparme por la programación de Cargo Cult? En este momento estoy feliz de que esté arreglado. :-) –

+0

Esto también solucionó mi problema. No estoy seguro de cómo hacer esto desde entonces. La consulta se ejecutó en 7 segundos y el procedimiento almacenado tardó más de 7 minutos. Usando variables locales se ejecuta en 6 segundos. ¡Gracias! – buzzzzjay

+0

Me quemo los 2 días para aumentar el rendimiento de mi procedimiento de tienda, tardó 1 minuto y 20 segundos para la ejecución, pero una vez que lo cambio completo con solo 3 segundos. ¡Gracias! :) – Hitusam

4

supongo que esto es causado por parametersniffing.

+0

+1 - fue para nosotros, seguimos la respuesta dada por [Adam Marshall] (http://stackoverflow.com/users/134653/adam -marshall) en [SO: SQL Server: Consulta rápida, pero lenta del procedimiento] (http://stackoverflow.com/questions/440944/sql-server-query-fast-but-slow-from-procedure) y redujo nuestro tiempo de ejecución sp de ** 20 MINUTOS ** a ** 4 SEGUNDOS ** –

3

La cuestión de por qué un lote necesita siempre para funcionar dentro de un procedimiento almacenado de SQL todavía funciona instantáneamente en SSMS tiene que ver con el parámetro de SQL oler, especialmente con los parámetros de fecha y hora.

Hay varios artículos excelentes sobre la detección de parámetros por ahí.

Aquí hay uno de ellos (no lo escribo, simplemente pasarlo).

http://www.sommarskog.se/query-plan-mysteries.html

3

Como otros han mencionado, esto podría ser un 'descubrimiento de parámetros' problema.Intente incluir la línea:

OPTION (RECOMPILE) 

al final de su consulta SQL.

Hay un artículo aquí explicando qué descubrimiento de parámetros es: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

+0

+1 - fue para nosotros, seguimos la respuesta dada por [Adam Marshall] (http://stackoverflow.com/users/134653/adam -marshall) en [SO: SQL Server: Consulta rápida, pero lenta del procedimiento] (http://stackoverflow.com/questions/440944/sql-server-query-fast-but-slow-from-procedure) y redujo nuestro tiempo de ejecución sp desde ** 20 MINUTOS ** hasta ** 4 SEGUNDOS ** –

1

yo también tiene el mismo problema hoy en día. He descartado y recreado el SP y funcionó. Esto es algo con caché SP y cuando se descarta el SP, el plan en caché se ha eliminado. Puede intentar lo mismo o usar 'DBCC FREEPROCCACHE' para borrar el caché.

Cuestiones relacionadas