Wprowadzenie
Optymalizator zapytań SQL Server korzysta ze statystyk podczas kompilowania zapytań, aby pomóc w określeniu optymalnego planu zapytań. Domyślnie, jeśli optymalizator zauważy, że statystyka jest nieaktualna z powodu zbyt wielu zmian w tabeli, zaktualizuje statystykę bezpośrednio przed kontynuowaniem kompilacji zapytania (tylko potrzebne statystyki, a nie wszystkie statystyki dla tabeli). .
Zwróć uwagę, że „zbyt wiele” jest niespecyficzne, ponieważ różni się w zależności od wersji i tego, czy flaga śledzenia 2371 jest włączona — zobacz sekcję AUTO_UPDATE_STATISTICS na tej stronie, aby uzyskać szczegółowe informacje.
Problem z synchronicznymi aktualizacjami statystyk
Synchroniczne aktualizowanie statystyk przed kompilacją oczywiście wprowadza opóźnienie i sprawia, że kompilacja i wykonanie zapytania trwa dłużej. Jak duże opóźnienie zależy od kilku czynników, w tym:
- Ile tabel objętych zapytaniem osiągnęło próg „zbyt wielu zmian”
- Ile statystyk dla każdej z tych tabel należy zaktualizować, ponieważ są one potrzebne do kompilacji
- Ile wierszy znajduje się w odpowiednich tabelach
- Opcje określone podczas tworzenia każdej statystyki (np. FULLSCAN i PERSIST_SAMPLE_PERCENT=ON)
Tak więc może wystąpić pozornie losowe opóźnienie, które może powodować problemy w niektórych scenariuszach, zwłaszcza jeśli aplikacja ma ustawiony bardzo niski limit czasu zapytania.
Unikanie synchronicznych aktualizacji statystyk
Istnieje wiele sposobów na uniknięcie synchronicznych aktualizacji statystyk, takich jak:
- Ustawienie AUTO_UPDATE_STATISTICS na OFF, które wyłącza wszystkie automatyczne aktualizacje i oznacza, że będziesz musiał przeprowadzić własną konserwację statystyk, aby uniknąć możliwości nieoptymalnych planów zapytań z nieaktualnych statystyk.
- Ustawienie AUTO_UPDATE_STATISTICS_ASYNC na ON, więc gdy optymalizator zauważy, że statystyka wymaga aktualizacji, kontynuuje kompilację, a zadanie w tle aktualizuje statystykę nieco później. Działa to tylko wtedy, gdy masz również opcję AUTO_UPDATE_STATISTICS ustawioną na ON.
- Regularnie przeprowadzaj konserwację statystyk, aby automatyczne synchroniczne lub asynchroniczne aktualizacje statystyk w ogóle się nie odbywały.
W społeczności SQL Server toczy się wiele dyskusji na temat włączenia asynchronicznych aktualizacji statystyk. Zapytałem moją uroczą żonę, Kimberly L. Tripp, jaka jest jej opinia, a ona zawsze zaleca jej włączenie, a o statystykach zapomniała więcej, niż kiedykolwiek będę wiedział, więc jej wierzę.
Śledzenie aktualizacji statystyk synchronicznych
Nigdy nie było oczywistego sposobu, aby stwierdzić, czy zapytanie trwało długo, ponieważ czekało na synchroniczną aktualizację statystyk. Możesz powiedzieć *po* zakończeniu aktualizacji statystyk, czy masz już uruchomioną sesję wydarzenia rozszerzonego, obserwującą auto_stats zdarzenia i filtrowanie na async kolumna ustawiona na 0. Jednak ta kolumna w danych wyjściowych zdarzenia została dodana tylko w SQL Server 2017, a ponadto trzeba było skonfigurować akcję, która przechwyciła coś, aby zidentyfikować zaangażowane zapytanie.
Teraz w SQL Server 2019 jest typ oczekiwania WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE i na pierwszy rzut oka wydaje się, że łatwo pozwoliłoby to sprawdzić, czy zapytanie czeka na synchroniczną aktualizację statystyk, po prostu zaglądając do sys.dm_os_waiting_tasks, aby zobaczyć, jakie jest aktualnie zapytanie czekam na.
Niestety tak nie jest.
Termin „czekanie” jest tutaj nieco mylący, ponieważ w tym przypadku wątek tak naprawdę nie czeka. Ten nowy typ oczekiwania jest przykładem tak zwanego oczekiwania „wywłaszczającego”, w którym wątek przełącza się w tryb, w którym pozostaje na procesorze, dopóki nie zakończy swojej pracy. Większość czekania z wywłaszczaniem ma miejsce, gdy wątek wykonuje wywołanie poza SQL Server (np. w celu uzyskania informacji o zabezpieczeniach z kontrolera domeny), ale czasami wątek robi coś wewnątrz SQL Server i musi to zakończyć, zanim zostanie potencjalnie zmuszony do udostępnienia procesora ponieważ jego kwant wątku 4 ms wygasł. Żadna z tych rzeczy nie jest tym, co się tutaj dzieje. W tym przypadku wątek rejestruje rozpoczęcie wywłaszczania z nowym typem oczekiwania, a następnie aktualizuje statystyki, prawdopodobnie powodując po drodze inne *prawdziwe* oczekiwania, takie jak PAGEIOLATCH_SH. Dopiero po zakończeniu aktualizacji statystyk oczekiwanie z wywłaszczaniem kończy się i jest uwzględniane w metrykach statystyk oczekiwania.
Dlaczego to wielka sprawa? Cóż, DMV sys.dm_os_waiting_tasks pokazuje typy oczekiwania dla wszystkich wątków, które *naprawdę* czekają, tj. na liście zadań oczekujących harmonogramu, więc jeśli wątek synchronicznej aktualizacji statystyk nie czeka na WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE, ten typ oczekiwania nie pojawi się na wyjściu DMV. Nowy typ oczekiwania nie może być użyty do sprawdzenia, czy zapytanie aktualnie oczekuje na aktualizację statystyk.
Możesz łatwo to sobie udowodnić, wykonując następujące czynności:
- Utwórz tabelę z kilkoma setkami tysięcy wierszy
- Utwórz statystykę w kolumnie tabeli i określ FULLSCAN i PERSIST_SAMPLE_PERCENT =ON jako opcje, wymuszając odczytywanie całej tabeli za każdym razem, gdy statystyka jest aktualizowana
- Zaktualizuj dwadzieścia tysięcy wierszy
- Sprawdź bazę danych i wykonaj DBCC DROPCLEANBUFFERS
- Wykonaj instrukcję SELECT z klauzulą WHERE w kolumnie z utworzoną statystyką
- Poszukaj w sys.dm_os_waiting_tasks DMV identyfikatora sesji SELECT, a zobaczysz, że prawdopodobnie czeka na PAGEIOLATCH_SH, gdy aktualizacja statystyk odczytuje tabelę
Pomijając to rozczarowanie, istnieje sztuczka, która pozwala sprawdzić, czy zapytanie czeka na synchroniczną aktualizację statystyk. Gdy nastąpi aktualizacja statystyk, uruchamiane jest polecenie o nazwie STATMAN i można to zobaczyć w danych wyjściowych z sys.dm_exec_requests :stan zostanie „zawieszony” (nawet jeśli wątek jest uruchomiony, jak opisałem powyżej), a polecenie będzie „WYBIERZ (STATMAN).”
Do czego służy nowy typ oczekiwania?
Chociaż nowy typ oczekiwania nie może być używany jako natychmiastowy sposób informowania, że zapytanie oczekuje na synchroniczną aktualizację statystyk, jeśli pojawia się on w zwykłej analizie statystyk oczekiwania, wiesz, że niektóre zapytania w obciążeniu mogą cierpieć z powodu tych opóźnień . Ale to jest granica jego użyteczności, jeśli o mnie chodzi. O ile średni czas oczekiwania nie wyświetla się jako niepokojący procent średniego czasu wykonania zapytania lub ciągle rejestrujesz oczekiwania w krótkich okresach czasu, aby umożliwić prawidłową analizę, nie masz pewności, czy występuje problem.
Jest to typ oczekiwania, w którym czas oczekiwania może się bardzo różnić, w zależności od czynników, o których wspomniałem wcześniej. Dlatego użyłbym tylko obecności tego typu oczekiwania, aby zostać ostrzeżonym o potencjalnych problemach, i chciałbym zaimplementować sesję Extended Event, jak opisano powyżej, aby przechwycić instancje synchronicznych aktualizacji statystyk, aby sprawdzić, czy ich czas trwania jest wystarczająco długi, aby zasługiwać podjęcie pewnych działań naprawczych.
Podsumowanie
Nie jestem pewien, czy dodanie typu oczekiwania WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE zmieni to, czy ludzie konfigurują asynchroniczne aktualizacje statystyk, czy po prostu wykonują same konserwacje statystyk, ale przynajmniej teraz będziesz w stanie stwierdzić, czy zapytania czekają na statystyki synchroniczne aktualizacje i podejmij dalsze działania.
Do następnego razu życzę miłego rozwiązywania problemów z wydajnością!