Próbuję zrozumieć problem, który mamy z SQL Server 2000. Jesteśmy witryną o umiarkowanie transakcyjnym charakterze i mamy zapisany proces, sp_GetCurrentTransactions
który akceptuje ID klienta i dwie daty.
Teraz, w zależności od dat i klienta, to zapytanie może zwrócić wszystko od zera do 1000 wierszy.
Problem: doświadczyliśmy tego, że nagle dostaniemy szereg błędów (typowych Execution Timeout Expired
lub podobnych) dla konkretnego klienta podczas próby wykonania zapisanego proc. Sprawdzamy więc zapytanie, uruchamiamy je w SSMS i stwierdzamy, że zajmuje ono 30 sekund. Ponownie kompilujemy zapisany proc i -bang- działa teraz za 300ms.
Rozmawiałem o tym z naszą DBA. Powiedział mi, że baza danych utworzyła plan zapytań, kiedy utworzyliśmy przechowywany proc. Powiedział, że był to dobry plan dla tego zestawu parametrów, ale jeśli rzucisz na niego pewien zestaw parametrów, wtedy plan nie będzie najlepszym planem dla tych danych, więc zobaczysz, że działa wolno.
Opcje przedstawione mi to przeniesienie tego problemu z przechowywanego proc i z powrotem do dynamicznego SQL, który ma plan wykonania tworzony przy każdym uruchomieniu.
To wydaje mi się krokiem wstecz i wydaje mi się, że musi być jakiś sposób na obejście tego. Czy istnieje inny sposób rozwiązania tego problemu?
Wszelkie odpowiedzi są mile widziane.
źródło
Odpowiedzi:
Ten problem nazywa się wąchaniem parametrów.
Późniejsze wersje SQL Server daje więcej możliwości w kontaktach z nim, takich jak
OPTION (RECOMPILE)
lubOPTIMIZE FOR
podpowiedzi.Możesz spróbować zadeklarować zmienne w procedurze przechowywanej, przypisując wartości parametrów do zmiennych i używając zmiennych zamiast parametrów, ponieważ brzmi to tak, jakbyś przez większość czasu miał dość zadowalający plan.
Zwykle najbardziej katastrofalnymi złymi planami są te opracowane dla parametrów o bardzo wysokiej selektywności, ale uruchomione z parametrami o niskiej selektywności.
Zakładając, że wygenerowany plan jest bardziej niezawodny dzięki temu podejściu i zadowalający dla wszystkich wartości parametrów, wówczas przewaga tego podejścia nad sugerowanym przez JNK polega na tym, że nie pociąga on za sobą kosztów kompilacji dla każdego połączenia.
Wadą jest to, że w przypadku niektórych wykonań czas wykonywania może być dłuższy niż w przypadku planu dostosowanego specjalnie do tych wartości parametrów, więc jest to kompromis między czasem kompilacji a czasem wykonania.
źródło
Zamiast używać dynamicznego SQL, zawsze możesz po prostu zmienić wywołania proc na:
EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE
Te
WITH RECOMPILE
siły (zgadliście!) Ponowną kompilację planu wykonania, gdy jest on prowadzony.Możesz również zawrzeć
WITH RECOMPILE
w definicji przechowywanego proc:źródło
Możesz także spróbować zdecydować, która baza danych będzie używana, choć będziesz trochę walczył z optymalizatorem, więc będzie bardziej kruchy, niż możesz się spodziewać.
Technika jest taka - podziel procedurę przechowywaną na 2, jeden przeznaczony dla jednego zestawu parametrów, jeden dla drugiego. Dodaj do nich klauzule where, aby między nimi obejmowały wszystkie możliwe przypadki. Spójrz na plany zapytań - jeden powinien być zoptymalizowany dla jednego zestawu parametrów, drugi dla drugiego zestawu. Być może trzeba będzie majstrować przy zapytaniu, aby tak się stało, lub może nie być to możliwe w przypadku zapytania, w takim przypadku to podejście nie zadziała.
Teraz spraw, aby oryginalna procedura przechowywana sprawdziła wartości parametrów i wysłała do odpowiedniej jednej z dwóch procedur przechowywanych z poprzedniego akapitu.
Może to działać, ale jest to rodzaj włamania, aby zmusić optymalizator do bardziej efektywnej pracy dla Twojego zapytania. Podobnie jak wszystkie takie hacki, w przyszłych wersjach bazy danych może to być niepotrzebne, a nawet pogorszyć sytuację. Więc nawet jeśli to działa, musisz zdecydować, czy warto.
źródło
Możesz także spróbować
SET FORCEPLAN
indeksować wskazówki.http://msdn.microsoft.com/en-us/library/ms188344.aspx
Zasadniczo pozwala wybrać kolejność łączenia.
Możesz mieć wskazówki dotyczące indeksów, aby upewnić się, że serwer SQL używa poprawnych indeksów.
źródło
Hmmm ... jeśli skupimy się tylko na tej jednej procedurze składowanej, byłbym zaskoczony, że użycie buforowanego planu wykonania spowoduje problem, który widzisz. Chciałbym zobaczyć plan wykonania procedury składowanej przy użyciu zestawu parametrów dla klienta i dwóch dat. Zastanawiam się, czy bardziej konkretny indeks byłby pomocny -> na przykład na customerId i tylko dwie daty?
źródło
Nagłe obniżenie wydajności wydaje się być nieefektywnym planem zapytań, który powstaje, prawdopodobnie w wyniku brakujących statystyk. Uruchom profilera programu SQL Server z ustawionymi kategoriami zdarzeń „Błędy i ostrzeżenia” i sprawdź, czy istnieją ostrzeżenia o brakujących statystykach.
Być może brakuje też indeksu lub może być konieczne jego defragmentowanie, ponieważ mogą być zbyt fragmentaryczne, aby można było z nich korzystać w programie SQL Server, co powoduje, że uważa się, że skanowanie tabeli spowoduje mniej operacji we / wy.
@JNK podnosi świetny punkt na temat przechowywanych procesów - są one kompilowane z góry, a plan zapytań będzie przechowywany wraz z procedurą przechowywaną.
Niekoniecznie zgadzam się na użycie Z RECOMPILE, ponieważ wtedy tracisz korzyści z zapisywania i ponownego wykorzystywania planu zapytań. W niektórych przypadkach jest to konieczne - np. Jeśli statystyki dystrybucji w tabelach leżących u podstaw różnią się znacznie między połączeniami, ale ogólnie, gdy dane w tabelach są dojrzałe, dystrybucja danych w tabelach będzie się minimalnie różnić.
Podsumowując:
źródło