Aby zakończyć moją krótką serię artykułów na temat zatrzasków, tym razem omówię kilka innych zatrzasków w SQL Server, które możesz zobaczyć od czasu do czasu, ale nie zasługują na pełny artykuł. Jak zwykle zdecydowanie polecam przeczytanie pierwszego posta z serii przed tym, aby mieć ogólną wiedzę na temat zatrzasków.
Zatrzask LOG_MANAGER
Zatrzask LOG_MANAGER jest używany do synchronizacji podczas niektórych operacji związanych z dziennikiem transakcji, a na bazę danych przypada jeden zatrzask LOG_MANAGER (ponieważ każda baza danych ma własnego menedżera dziennika). Można go uzyskać tylko w trybie wyłączności i może stanowić wąskie gardło podczas wzrostu pliku dziennika transakcji. Scenariusz, w którym stanie się to oczywistym problemem, to:
- Plik dziennika ma mały zestaw automatycznego wzrostu
- Istnieje wiele jednoczesnych połączeń generujących rekordy dziennika transakcji
- Plik dziennika musi się rozrastać
Gdy w pliku dziennika zabraknie miejsca, będzie musiał rosnąć. Pierwszy wątek, który realizuje więcej miejsca w dzienniku, uzyskuje zatrzask LOG_MANAGER w trybie EX i przystępuje do powiększania pliku dziennika. Wiele innych wątków nadal próbuje generować rekordy dziennika i trafiać do kolejki dla zatrzasku LOG_MANAGER, dzięki czemu mogą powiększać plik dziennika. Kiedy pierwszy wątek zwolni zatrzask, następny go dostanie i uświadamia sobie, że dziennik już urósł, więc odrzuca go i kontynuuje. I tak dalej i tak dalej. Nawiasem mówiąc, ten wzorzec wąskiego gardła nazywa się konwojem zatrzaskowym .
Możesz myśleć o tym jako dokładnie o tym samym wąskim gardle, co w przypadku zatrzasku FGCB_ADD_REMOVE, o którym mówiłem wcześniej w serii, ale ze wzrostem pliku dziennika zamiast wzrostu pliku danych. Jednak z zatrzaskiem FGCB_ADD_REMOVE, zwykle instancja ma włączoną natychmiastową inicjalizację pliku, więc wzrost pliku jest bardzo szybki, ale z zatrzaskiem LOG_MANAGER, dziennik *musi* być zainicjowany na zero, a czas stracony w kolejce zatrzasku jest dłuższy .
Rozwiązanie tego wąskiego gardła składa się z trzech części:
- Ustaw prawidłowy automatyczny wzrost pliku dziennika, aby dziennik nie był zbyt często powiększany
- Dostosuj rozmiar dziennika do obciążenia, więc dziennik nie powinien w ogóle rosnąć
- Upewnij się, że dziennik jest czyszczony prawidłowo, aby dziennik nie musiał się powiększać
Jeśli to wszystko jest na miejscu, nie powinieneś widzieć, że zatrzask LOG_MANAGER jest zwykłym wąskim gardłem i mówię o tym więcej w moim poście tutaj.
Zatrzask ACCESS_METHODS_DATASET_PARENT
Podczas uzyskiwania dostępu do sterty lub indeksu wewnętrznie istnieje obiekt o nazwie odpowiednio HeapDataSetSession lub IndexDataSetSession. Kiedy wykonywane jest skanowanie równoległe, każdy z wątków wykonujących rzeczywistą pracę skanowania ma „podrzędny” zestaw danych (kolejne wystąpienie dwóch obiektów, które właśnie opisałem), a główny zestaw danych, który naprawdę kontroluje skanowanie, jest nazywany „rodzic”.
Gdy jeden z wątków roboczych skanowania wyczerpie zestaw wierszy, które ma przeskanować, musi uzyskać nowy zakres, uzyskując dostęp do nadrzędnego zestawu danych, co oznacza uzyskanie zatrzasku ACCESS_METHODS_DATASET_PARENT w trybie wyłączności. Chociaż może się to wydawać wąskim gardłem, tak naprawdę nie jest i nie możesz nic zrobić, aby powstrzymać wątki wykonujące skanowanie równoległe przed od czasu do czasu wyświetlaniem oczekiwania LATCH_EX na ten zatrzask.
Pytanie, które powinieneś sobie zadać, brzmi:czy to zapytanie powinno w pierwszej kolejności wykonywać skanowanie równoległe? Jest całkowicie możliwe, że coś się wydarzyło, aby zmusić plan zapytania do włączenia skanowania równoległego, gdy może to nie być najskuteczniejszy sposób uruchomienia zapytania. Przykłady rzeczy, które mogą spowodować zmianę planu na skanowanie równoległe to:
- Nieaktualne statystyki
- Brakujący lub porzucony indeks nieklastrowany
- Nowy kod wymuszający skanowanie z powodu niejawnej konwersji — niezgodność typu danych między kolumną a zmienną/parametrem, co wyklucza użycie indeksu nieklastrowego
- Nowy kod wymuszający skanowanie, ponieważ arytmetyka jest wykonywana na kolumnie tabeli zamiast na zmiennej/parametrze, co ponownie wyklucza użycie indeksu nieklastrowanego
- Występujący wzrost danych i skanowanie to naprawdę najbardziej wydajny plan
Lub może być tak, że to zapytanie wymaga skanowania, w którym to przypadku LATCH_EX czeka, aż ACCESS_METHODS_DATASET_PARENT są tylko częścią twojego środowiska.
Zatrzask ACCESS_METHODS_HOBT_VIRTUAL_ROOT
Każde wystąpienie tego zatrzasku chroni wpis w metadanych Storage Engine dla b-drzewa, w szczególności identyfikator strony głównej strony b-drzewa (strona u góry trójkąta, którą zwykle traktujemy jako indeks) . Mówię konkretnie b-drzewo a nie indeks , ponieważ indeks może mieć wiele partycji, z których każda ma b-drzewo (zasadniczo część ogólnego indeksu, ale z ograniczeniami klucza niskiej wartości i wysokiej wartości).
Za każdym razem, gdy wątek musi przejść przez b-drzewo, musi zaczynać się na stronie głównej i przechodzić w dół do poziomu liścia. Aby odczytać metadane zawierające identyfikator strony głównej, wątek musi uzyskać zatrzask ACCESS_METHODS_HOBT_VIRTUAL_ROOT w trybie SH, aby upewnić się, że identyfikator strony nie jest w trakcie zmiany. Gdy wątek musi zmienić identyfikator strony głównej, musi uzyskać zatrzask w trybie EX.
Dlaczego strona główna b-drzewa miałaby się kiedykolwiek zmienić? Wraz ze wzrostem liczby rekordów indeksu na stronie głównej, w końcu zostanie ona zapełniona i nastąpi podział strony. Kiedy tak się dzieje, bieżąca strona główna i strona, na którą się dzieli, stają się nowym poziomem w b-drzewie i tworzona jest zupełnie nowa strona główna z dwoma rekordami indeksu wskazującymi na starą stronę główną i stronę, którą podzielony na. Nowy identyfikator strony głównej musi być wprowadzony do metadanych, aby zatrzask jest pobierany w trybie EX. Stanie się to kilka razy szybko, ponieważ indeks w pustej tabeli zacznie być zapełniany przez wstawki, ale nie jest to coś, co zobaczysz jako ciągły problem z wąskim gardłem wydajności.
Podsumowanie
Jak na pewno dowiedziałeś się z tej serii, zrozumienie zatrzasków i wąskich gardeł zatrzasków wymaga nieco większej wiedzy o tym, co dzieje się w silniku pamięci masowej, niż o ogólnej analizie statystyk oczekiwania.
Zwykle radzę ludziom *nie* rozpoczynać rozwiązywania problemów z wydajnością, patrząc na statystyki latch (poprzez sys.dm_os_latch_stats ), ale zamiast tego zawsze zaczynaj od statystyk oczekiwania (zobacz mój post tutaj) i zagłębiaj się w zatrzaski tylko wtedy, gdy LATCH_EX lub LATCH_SH są jednymi z najczęstszych oczekiwań w instancji SQL Server.
Jeśli masz jakiekolwiek pytania dotyczące zatrzasków, napisz do mnie.