Napotkałem dziwną sytuację, gdy dołączałem OPTION (RECOMPILE)
do mojego zapytania powoduje, że działa ono w pół sekundy, podczas gdy jego pominięcie powoduje, że zapytanie trwa znacznie ponad pięć minut.
Dzieje się tak, gdy zapytanie jest wykonywane z programu Query Analyzer lub z mojego programu C # za pośrednictwem SqlCommand.ExecuteReader()
. Dzwonienie (lub nie dzwonienie) DBCC FREEPROCCACHE
lub DBCC dropcleanbuffers
nie ma znaczenia; Wyniki zapytania są zawsze zwracane natychmiastowo OPTION (RECOMPILE)
i dłużej niż pięć minut bez niego. Zapytanie jest zawsze wywoływane z tymi samymi parametrami [na potrzeby tego testu].
Używam SQL Server 2008.
Jestem dość komfortowy w pisaniu SQL, ale nigdy wcześniej nie użyłem OPTION
polecenia w zapytaniu i nie byłem zaznajomiony z całą koncepcją pamięci podręcznych planu do czasu skanowania postów na tym forum. Z postów rozumiem, że OPTION (RECOMPILE)
jest to kosztowna operacja. Najwyraźniej tworzy nową strategię wyszukiwania dla zapytania. Dlaczego więc tak się dzieje, że kolejne zapytania pomijają rozszerzenieOPTION (RECOMPILE)
są tak wolne? Czy kolejne zapytania nie powinny wykorzystywać strategii wyszukiwania, która została obliczona podczas poprzedniego wywołania, które zawierało wskazówkę dotyczącą ponownej kompilacji?
Czy zapytanie wymagające rekompilacji przy każdym wywołaniu jest bardzo niezwykłe?
Przepraszam za pytanie dla początkujących, ale naprawdę nie mogę się z tym pogodzić.
AKTUALIZACJA: Poproszono mnie o wysłanie zapytania ...
select acctNo,min(date) earliestDate
from(
select acctNo,tradeDate as date
from datafeed_trans
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_money
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_jnl
where feedid=@feedID and feedDate=@feedDate
)t1
group by t1.acctNo
OPTION(RECOMPILE)
Uruchamiając test z Query Analyzer, poprzedzam następujące wiersze:
declare @feedID int
select @feedID=20
declare @feedDate datetime
select @feedDate='1/2/2009'
Podczas wywoływania go z mojego programu C # parametry są przekazywane za pośrednictwem SqlCommand.Parameters
właściwości.
Na potrzeby tej dyskusji można założyć, że parametry nigdy się nie zmieniają, więc możemy wykluczyć nieoptymalny parametr pachnący jako przyczynę.
źródło
X = @X OR @X IS NULL
sięX=@X
i wykonywanie wyszukiwania Zobacz tutaj lub przesuwanie predykatów dalej w dół w stosunku do widoku z funkcjami oknaRECOMPILE
. W każdym przypadku zapisz plany wykonania i przyjrzyj się różnicom.Odpowiedzi:
Czasami używanie
OPTION(RECOMPILE)
ma sens. Z mojego doświadczenia wynika, że jedyną realną opcją jest użycie dynamicznego SQL. Zanim zbadasz, czy ma to sens w Twojej sytuacji, poleciłbym odbudować statystyki. Można to zrobić, uruchamiając następujące polecenie:A następnie odtworzenie planu wykonania. Zapewni to, że po utworzeniu planu wykonania będzie on korzystał z najnowszych informacji.
Dodanie
OPTION(RECOMPILE)
odbudowuje plan wykonania za każdym razem, gdy wykonywane jest zapytanie. Nigdy nie słyszałem, żeby to zostało opisane jako,creates a new lookup strategy
ale może używamy po prostu innych terminów do tego samego.Kiedy tworzona jest procedura składowana (podejrzewam, że wywołujesz ad-hoc sql z .NET, ale jeśli używasz sparametryzowanego zapytania, to kończy się to wywołaniem przechowywanej procedury ) SQL Server próbuje określić najbardziej efektywny plan wykonania dla tego zapytania na podstawie danych w bazie danych i przekazanych parametrów ( wykrywanie parametrów ), a następnie buforuje ten plan. Oznacza to, że jeśli utworzysz zapytanie, w którym znajduje się 10 rekordów w bazie danych, a następnie wykonasz je, gdy będzie 100 000 000 rekordów, buforowany plan wykonania może już nie być najbardziej efektywny.
Podsumowując - nie widzę tutaj żadnego powodu, dla którego
OPTION(RECOMPILE)
byłaby to korzyść. Podejrzewam, że wystarczy zaktualizować statystyki i plan wykonania. Odbudowywanie statystyk może być istotną częścią pracy DBA w zależności od Twojej sytuacji. Jeśli nadal masz problemy po zaktualizowaniu swoich statystyk, sugerowałbym opublikowanie obu planów wykonania.Odpowiadając na twoje pytanie - tak, powiedziałbym, że jest bardzo nietypowe, aby najlepszą opcją była rekompilacja planu wykonania za każdym razem, gdy wykonujesz zapytanie.
źródło
OPTION (RECOMPILE)
może być jedynym rozwiązaniem.Często, gdy występuje drastyczna różnica między uruchomieniem a uruchomieniem zapytania, okazuje się, że często jest to jeden z 5 problemów.
STATYSTYKA- Statystyki są nieaktualne. Baza danych przechowuje statystyki dotyczące zakresu i rozkładu typów wartości w różnych kolumnach tabel i indeksów. Pomaga to silnikowi zapytań w opracowaniu „Planu” ataku dotyczącego sposobu wykonania zapytania, na przykład typu metody, której użyje do dopasowania kluczy między tabelami przy użyciu skrótu lub przeglądania całego zestawu. Możesz wywołać Update Statistics dla całej bazy danych lub tylko dla niektórych tabel lub indeksów. Spowalnia to kwerendę z jednego uruchomienia do drugiego, ponieważ gdy statystyki są nieaktualne, prawdopodobnie plan kwerend nie jest optymalny dla nowo wstawionych lub zmienionych danych dla tego samego zapytania (wyjaśnione poniżej). Natychmiastowe aktualizowanie statystyk w bazie danych produkcyjnych może nie być właściwe, ponieważ w zależności od ilości danych do próbkowania wystąpi pewne obciążenie, spowolnienie i opóźnienia. Możesz także użyć pełnego skanowania lub próbkowania, aby zaktualizować statystyki. Jeśli spojrzysz na plan zapytań, możesz również wyświetlić statystyki dotyczące używanych indeksów, na przykład za pomocą poleceniaDBCC SHOW_STATISTICS (nazwa tabeli, nazwa indeksu) . To pokaże dystrybucję i zakresy kluczy, na których opiera się plan kwerend.
PRZESYKANIE PARAMETRÓW - Plan zapytania, który jest buforowany, nie jest optymalny dla określonych przekazywanych parametrów, mimo że samo zapytanie nie uległo zmianie. Na przykład, jeśli przekażesz parametr, który pobiera tylko 10 z 1 000 000 wierszy, wówczas utworzony plan kwerend może używać Hash Join, jednak jeśli przekazany parametr użyje 750 000 z 1 000 000 wierszy, utworzony plan może być skanowanie indeksu lub skanowanie tabeli. W takiej sytuacji możesz nakazać instrukcji SQL użycie opcji OPCJA (REKOMPILACJA) lub SP, aby użyć Z REKOMPILEJ. Aby poinformować Silnik, że jest to „Plan jednorazowego użytku” i nie używać planu buforowanego, który prawdopodobnie nie ma zastosowania. Nie ma reguły, jak podjąć taką decyzję, zależy to od znajomości sposobu wykorzystania zapytania przez użytkowników.
INDEKSY - Możliwe, że zapytanie nie uległo zmianie, ale zmiana w innym miejscu, taka jak usunięcie bardzo użytecznego indeksu, spowolniła zapytanie.
ZMIENIONO WIERSZE - Wiersze , o które pytasz, drastycznie zmieniają się w zależności od połączenia. W takich przypadkach statystyki są zwykle aktualizowane automatycznie. Jeśli jednak tworzysz dynamiczny SQL lub wywołujesz SQL w ciasnej pętli, istnieje możliwość, że używasz przestarzałego planu zapytań opartego na niewłaściwej drastycznej liczbie wierszy lub statystyk. Ponownie w tym przypadku OPCJA (RECOMPILE) jest przydatna.
LOGIKA To logika, twoje zapytanie nie jest już wydajne, było w porządku dla małej liczby wierszy, ale już nie jest skalowane. Zwykle wiąże się to z bardziej dogłębną analizą planu zapytania. Na przykład nie możesz już robić rzeczy zbiorczo, ale musisz robić fragmenty i wykonywać mniejsze zatwierdzenia, lub twój cross product był w porządku dla mniejszego zestawu, ale teraz zajmuje procesor i pamięć, ponieważ skaluje się większy, może to również dotyczyć używając DISTINCT, wywołujesz funkcję dla każdego wiersza, twoje dopasowania kluczy nie używają indeksu z powodu konwersji typu CASTING lub NULLS lub funkcji ... Zbyt wiele możliwości tutaj.
Generalnie, kiedy piszesz zapytanie, powinieneś mieć w umyśle pewien obraz tego, jak z grubsza są rozprowadzane określone dane w Twojej tabeli. Na przykład kolumna może mieć równomiernie rozłożoną liczbę różnych wartości lub może być pochylona, 80% czasu ma określony zestaw wartości, niezależnie od tego, czy rozkład będzie się często zmieniał w czasie, czy będzie dość statyczny. Dzięki temu lepiej zrozumiesz, jak zbudować wydajne zapytanie. Ale także podczas debugowania wydajności zapytania mają podstawę do budowania hipotezy, dlaczego jest powolna lub nieefektywna.
źródło
Aby dodać do doskonałej listy (podanej przez @CodeCowboyOrg) sytuacji, w których OPCJA (RECOMPILE) może być bardzo pomocna,
źródło
Pierwszą czynnością przed dostrojeniem zapytań jest defragmentacja / odbudowa indeksów i statystyk, w przeciwnym razie tracisz czas.
Musisz sprawdzić plan wykonania, aby zobaczyć, czy jest stabilny (jest taki sam, gdy zmieniasz parametry), jeśli nie, być może będziesz musiał utworzyć indeks okładki (w tym przypadku dla każdej tabeli) (wiedząc, że system możesz utworzyć taki, który jest przydatny również w przypadku innych zapytań).
jako przykład: utwórz indeks idx01_datafeed_trans On datafeed_trans (feedid, feedDate) INCLUDE (acctNo, tradeDate)
jeśli plan jest stabilny lub możesz go ustabilizować, możesz wykonać zdanie za pomocą sp_executesql ('zdanie sql'), aby zapisać i użyć ustalonego planu wykonania.
jeśli plan jest niestabilny, musisz użyć instrukcji ad-hoc lub EXEC („zdanie sql”), aby za każdym razem ocenić i utworzyć plan wykonania. (lub procedura składowana „z rekompilacją”).
Mam nadzieję, że to pomoże.
źródło
Nekroję to pytanie, ale jest wyjaśnienie, którego nikt nie rozważał.
STATYSTYKI - statystyki nie są dostępne lub wprowadzają w błąd
Jeśli wszystkie poniższe stwierdzenia są prawdziwe:
W takim przypadku serwer sql może błędnie zakładać, że kolumny są nieskorelowane, co prowadzi do niższych niż oczekiwano oszacowań liczności przy stosowaniu zarówno ograniczeń, jak i wybierania planu wykonania o złym charakterze. Rozwiązaniem w tym przypadku byłoby utworzenie obiektu statystyki łączącego dwie kolumny, co nie jest kosztowną operacją.
źródło