2010-10-22 17 views
31

Wykonuję testy przy użyciu profilera SQL 2005.Zapytanie działa szybko, ale działa wolno w procedurze przechowywanej.

Mam procedura składowana, która po prostu uruchamia jedno zapytanie SQL.

Po uruchomieniu procedury przechowywanej zajmuje to dużo czasu i wykonuje 800 000 odczytów dysków.

Po uruchomieniu tego samego zapytania oddzielnie do procedury przechowywanej, odczytuje on 14 000 dysków.

Znalazłem, że jeśli uruchomię to samo zapytanie z OPTION (rekompilacja), wymaga to 800 000 odczytów dysku.

Z tego powodu robię (prawdopodobnie błędne) założenie, że procedura składowana rekompiluje się za każdym razem, a to powoduje problem.

Czy ktoś może rzucić trochę światła na to?

Ustawiłem ARITHABORT na. (Ten rozwiązał podobny problem na stackoverflow, ale nie rozwiąże moje)

Oto cała procedura przechowywana:

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 

Oto skrypt biegnę, który demonstruje problem:

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

Jaka jest różnica między tymi dwoma "rzeczywistymi planami wykonania kwerend"? – Andomar

Odpowiedz

61

OK, już wcześniej mieliśmy podobne problemy.

Sposób naprawiliśmy ten był poprzez lokalne parametry wewnątrz SP, tak że

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 

Następnie używamy lokalnych parametrów wewnątrz SP zamiast parametrów, który został przekazany w.

Zwykle naprawia to problem dla Nas.

Wierzymy, że jest to ze względu na parametr wąchania, ale nie ma żadnego dowodu, przepraszam ... X-)

EDIT:

Wystarczy popatrzeć na Different Approaches to Correct SQL Server Parameter Sniffing dla niektórych wnikliwych przykładach wyjaśnienia i poprawki.

+3

A teraz procedura przechowywana idzie tak szybko, że ma 0 czas trwania w profilera. Nie do wiary. Czy powinienem martwić się programowaniem Cargo Kultu? Teraz po prostu cieszę się, że jest naprawiony. :-) –

+0

To również naprawiło mój problem. Nie jestem pewien, jak to się stało. Zapytanie trwało 7 sekund, a procedura składowana trwała ponad 7 minut. Używanie zmiennych lokalnych uruchamia się w 6 sekund. Dzięki! – buzzzzjay

+0

Spalam moje 2 dni na zwiększenie wydajności mojej procedury sklepu, zajęło 1 minutę i 20 sekund na wykonanie, ale raz zmieniam ją w zaledwie 3 sekundy. Dzięki! :) – Hitusam

4

Chyba jest to spowodowane przez parametersniffing.

+0

+1 - to było dla nas, poszliśmy za odpowiedzią udzieloną przez [Adam Marshall] (http://stackoverflow.com/users/134653/adam -marshall) w [SO: SQL Server: zapytanie szybkie, ale wolne od procedury] (http://stackoverflow.com/questions/440944/sql-server-query-fast-but-slow-from-procedure) i zredukowane nasz czas pracy sp od ** 20 MINUT ** do ** 4 SEKUND ** –

3

Kwestia dlaczego partia trwa wiecznie, aby uruchomić wewnątrz SQL procedura przechowywana jeszcze działa natychmiastowo w SSMS ma do czynienia z SQL parametr wąchania, zwłaszcza z parametrami datetime.

Istnieje kilka doskonałych artykułów na temat sniffowania parametrów.

Oto jeden z nich (nie napisałem tego, tylko go podałem).

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

3

Jak wspominają inni, to może być 'parametr wąchania' problem.Spróbuj dodać linię:

OPTION (RECOMPILE) 

na końcu zapytania SQL.

Jest artykuł o wyjaśniając co parametr wąchania jest: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

+0

+1 - to było dla nas, poszliśmy za odpowiedzią udzieloną przez [Adam Marshall] (http://stackoverflow.com/users/134653/adam -marshall) w [SO: SQL Server: zapytanie szybkie, ale wolne od procedury] (http://stackoverflow.com/questions/440944/sql-server-query-fast-but-slow-from-procedure) i zredukowane nasze środowisko uruchomieniowe sp z ** 20 MINUT ** do ** 4 SEKUND ** –

1

Ja też mam ten sam problem dzisiaj. Rzuciłem i odtworzyłem SP i zadziałało. To jest coś z pamięcią podręczną SP i po upuszczeniu SP buforowany plan został usunięty. Możesz spróbować tego samego lub użyć "DBCC FREEPROCCACHE", aby usunąć pamięć podręczną.

Powiązane problemy