Benjamin Nevarez jest niezależnym konsultantem z Los Angeles w Kalifornii, który specjalizuje się w dostrajaniu i optymalizacji zapytań SQL Server. Jest autorem „SQL Server 2014 Query Tuning &Optimization” i „Inside the SQL Server Query Optimizer” oraz współautorem „SQL Server 2012 Internals”. Mając ponad 20-letnie doświadczenie w relacyjnych bazach danych, Benjamin był również prelegentem na wielu konferencjach poświęconych SQL Server, w tym PASS Summit, SQL Server Connections i SQLBits. Blog Benjamina można znaleźć na http://www.benjaminnevarez.com i można się z nim również skontaktować przez e-mail na adres admin na benjaminnevarez dot com i na Twitterze na @BenjaminNevarez.
Czy kiedykolwiek znalazłeś regresję planu po uaktualnieniu SQL Server i chciałeś wiedzieć, jaki był poprzedni plan wykonania? Czy kiedykolwiek miałeś problem z wydajnością zapytania spowodowany tym, że zapytanie nieoczekiwanie otrzymało nowy plan wykonania? Na ostatnim PASS Summit Conor Cunningham odkrył nową funkcję SQL Server, która może być pomocna w rozwiązywaniu problemów z wydajnością związanych z tymi i innymi zmianami w planach wykonania.
Ta funkcja, zwana magazynem zapytań, może pomóc w rozwiązywaniu problemów z wydajnością związanych ze zmianami planu i będzie dostępna wkrótce w SQL Azure, a później w następnej wersji SQL Server. Chociaż oczekuje się, że będzie on dostępny w Enterprise Edition programu SQL Server, nie wiadomo jeszcze, czy będzie dostępny w wersji Standard, czy jakichkolwiek innych. Aby zrozumieć zalety magazynu zapytań, omówię krótko proces rozwiązywania problemów z zapytaniami.
Dlaczego zapytania są wolne?
Po wykryciu, że problem z wydajnością wynika z powolnego zapytania, następnym krokiem jest ustalenie przyczyny. Oczywiście nie każdy problem wiąże się ze zmianami planów. Może być wiele powodów, dla których zapytanie, które działa dobrze, nagle staje się wolne. Czasami może to być związane z blokowaniem lub problemem z innymi zasobami systemowymi. Coś innego mogło się zmienić, ale wyzwaniem może być dowiedzenie się, co. Wiele razy nie mamy informacji o wykorzystaniu zasobów systemowych, statystykach wykonywania zapytań czy historii wydajności. I zwykle nie mamy pojęcia, jaki był stary plan. Może się zdarzyć, że jakaś zmiana, na przykład danych, schematu lub parametrów zapytania, spowodowała, że procesor zapytań utworzy nowy plan.
Zmiany planu
Podczas sesji Conor użył narzędzia Picasso Database Query Optimizer Visualizer, chociaż nie wymienił go z nazwy, aby pokazać, dlaczego plany w tym samym zapytaniu uległy zmianie, i wyjaśnił fakt, że różne plany mogą być wybrane dla tego samego zapytania na podstawie selektywność ich predykatów. Wspomniał nawet, że zespół zajmujący się optymalizacją zapytań korzysta z tego narzędzia, które zostało opracowane przez Indyjski Instytut Nauki. Przykład wizualizacji (kliknij, aby powiększyć):
Wizualizator Optymalizatora zapytań bazy danych Picassa
Każdy kolor na diagramie jest innym planem, a każdy plan jest wybierany na podstawie selektywności predykatów. Ważnym faktem jest to, że po przekroczeniu granicy na wykresie i wybraniu innego planu, w większości przypadków koszt i wydajność obu planów powinny być podobne, ponieważ selektywność lub szacowana liczba wierszy zmieniła się tylko nieznacznie. Może się to zdarzyć na przykład, gdy do tabeli zostanie dodany nowy wiersz, który kwalifikuje się do używanego predykatu. Jednak w niektórych przypadkach, głównie ze względu na ograniczenia w modelu kosztów optymalizatora zapytań, w którym nie jest on w stanie poprawnie zamodelować czegoś, nowy plan może mieć dużą różnicę wydajności w porównaniu z poprzednim, stwarzając problem dla Twojej aplikacji. Nawiasem mówiąc, plany pokazane na diagramie są ostatecznym planem wybranym przez optymalizator zapytań, nie myl tego z wieloma alternatywami, które optymalizator musi rozważyć, aby wybrać tylko jedną.
Moim zdaniem ważnym faktem, którego Conor nie omówił bezpośrednio, była zmiana planów z powodu regresji po zmianach dotyczących aktualizacji zbiorczych (CU), dodatków Service Pack lub aktualizacji wersji. Głównym problemem, który przychodzi na myśl przy zmianach w optymalizatorze zapytań, są regresje planu. Strach przed regresją planu został uznany za największą przeszkodę w ulepszeniu optymalizatora zapytań. Regresje to problemy pojawiające się po zastosowaniu poprawki w optymalizatorze zapytań i czasami określane jako klasyczne „dwa lub więcej błędów naprawiają”. Może się tak zdarzyć, gdy na przykład dwie złe oceny, jedna zawyżająca wartość, a druga ją niedoszacowująca, znoszą się wzajemnie, dając na szczęście dobre oszacowanie. Korekta tylko jednej z tych wartości może teraz prowadzić do złego oszacowania, co może negatywnie wpłynąć na wybór planu, powodując regresję.
Co robi magazyn zapytań?
Conor wspomniał, że Query Store działa i może pomóc w następujących kwestiach:
- Przechowuj historię planów zapytań w systemie;
- Uchwyć wydajność każdego planu zapytań w czasie;
- Zidentyfikuj zapytania, które „ostatnio stały się wolniejsze”;
- Pozwól szybko wymusić plany; i,
- Upewnij się, że działa to w przypadku restartów serwera, uaktualnień i ponownych kompilacji zapytań.
Tak więc ta funkcja nie tylko przechowuje plany i powiązane informacje o wydajności zapytań, ale może również pomóc w łatwym wymuszenie starego planu zapytań, co w wielu przypadkach może rozwiązać problem z wydajnością.
Jak korzystać ze sklepu z zapytaniami
Musisz włączyć magazyn zapytań za pomocą ALTER DATABASE CURRENT SET QUERY_STORE = ON;
oświadczenie. Wypróbowałem to w mojej obecnej subskrypcji SQL Azure, ale instrukcja zwróciła błąd, ponieważ wydaje się, że funkcja nie jest jeszcze dostępna. Skontaktowałem się z Conorem i powiedział mi, że ta funkcja będzie wkrótce dostępna.
Po włączeniu magazynu zapytań rozpocznie się zbieranie planów i danych dotyczących wydajności zapytań, które można analizować, przeglądając tabele magazynu zapytań. Obecnie widzę te tabele w SQL Azure, ale ponieważ nie mogłem włączyć magazynu zapytań, katalogi nie zwróciły żadnych danych.
Zebrane informacje można analizować proaktywnie, aby zrozumieć zmiany wydajności zapytań w aplikacji, lub z mocą wsteczną w przypadku problemów z wydajnością. Po zidentyfikowaniu problemu możesz użyć tradycyjnych technik dostrajania zapytań, aby spróbować rozwiązać problem, lub możesz użyć sp_query_store_force_plan
procedura składowana w celu wymuszenia poprzedniego planu. Plan musi zostać przechwycony w magazynie zapytań, aby został wymuszony, co oczywiście oznacza, że jest to prawidłowy plan (przynajmniej w momencie, gdy został zebrany; więcej o tym później) i został wcześniej wygenerowany przez optymalizator zapytań. Aby wymusić plan, potrzebujesz plan_id
, dostępny w sys.query_store_plan
katalog. Gdy spojrzysz na różne przechowywane metryki, które są bardzo podobne do przechowywanych na przykład w sys.dm_exec_query_stats
, możesz podjąć decyzję o optymalizacji pod kątem określonej metryki, takiej jak CPU, I/O itp. Następnie możesz po prostu użyć następującej instrukcji:
EXEC sys.sp_query_store_force_plan @query_id = 1, @plan_id = 1;
To mówi SQL Serverowi, aby wymusić plan 1 na zapytanie 1. Technicznie można zrobić to samo, korzystając z przewodnika po planie, ale byłoby to bardziej skomplikowane i musiałbyś ręcznie zebrać i znaleźć wymagany plan w pierwszej kolejności.
Jak działa magazyn zapytań?
W rzeczywistości wymuszanie planu wykorzystuje przewodniki planu w tle. Conor wspomniał, że „kiedy kompilujesz zapytanie, domyślnie dodajemy wskazówkę dotyczącą USE PLAN z fragmentem planu XML powiązanego z tą instrukcją”. Dzięki temu nie musisz już korzystać z przewodnika po planie. Należy również pamiętać, że podobnie jak w przypadku korzystania z przewodnika po planie, nie ma gwarancji, że będzie dokładnie wymuszony plan, ale przynajmniej coś do niego podobnego. Aby przypomnieć sobie, jak działają przewodniki po planach, zajrzyj do tego artykułu. Ponadto należy mieć świadomość, że w niektórych przypadkach wymuszenie planu nie działa, typowym przykładem jest zmiana schematu, tj. jeśli plan składowany używa indeksu, ale indeks już nie istnieje. W takim przypadku SQL Server nie może wymusić planu, wykona normalną optymalizację i zarejestruje fakt, że wymuszenie operacji planu nie powiodło się w sys.query_store_plan
katalog.
Architektura
Za każdym razem, gdy SQL Server kompiluje lub wykonuje zapytanie, do magazynu zapytań wysyłany jest komunikat. Jest to pokazane dalej.
Omówienie przepływu pracy magazynu zapytań
Informacje o kompilacji i wykonaniu są najpierw przechowywane w pamięci, a następnie zapisywane na dysku, w zależności od konfiguracji Query Store (dane są agregowane zgodnie z INTERVAL_LENGTH_MINUTES
parametr, który domyślnie wynosi jedną godzinę i jest opróżniany na dysk zgodnie z DATA_FLUSH_INTERVAL_SECONDS
parametr). Dane można również opróżnić na dysk, jeśli w systemie występuje presja pamięci. W każdym razie będziesz mógł uzyskać dostęp do wszystkich danych, zarówno w pamięci, jak i na dysku, po uruchomieniu sys.query_store_runtime_stats
katalog.
Katalogi
Zebrane dane są utrwalane na dysku i przechowywane w bazie danych użytkownika, w której włączony jest magazyn zapytań (a ustawienia są przechowywane w sys.database_query_store_options
. Katalogi Query Store to:
sys.query_store_query_text | Zapytanie o informacje tekstowe |
sys.query_store_query | Tekst zapytania oraz używany plan wpływające na opcje SET |
sys.query_store_plan | Plany wykonania, w tym historia |
sys.query_store_runtime_stats | Statystyki wykonywania zapytań |
sys.query_store_runtime_stats_interval | Czas rozpoczęcia i zakończenia interwałów |
sys.query_context_settings | Informacje o ustawieniach kontekstu zapytań |
Wyświetlenia zapytań w sklepie
Statystyki środowiska wykonawczego obejmują całą masę danych, w tym średnią, ostatnią, minimalną, maksymalną i odchylenie standardowe. Oto pełny zestaw kolumn dla sys.query_store_runtime_stats
:
runtime_stats_id | plan_id | runtime_stats_interval_id | ||
execution_type | execution_type_desc | first_execution_time | last_execution_time | count_executions |
avg_duration | last_duration | min_duration | max_duration | stdev_duration |
avg_cpu_time | last_cpu_time | min_cpu_time | max_cpu_time | stdev_cpu_time |
avg_logical_io_reads | last_logical_io_reads | min_logical_io_reads | max_logical_io_reads | stdev_logical_io_reads |
avg_logical_io_writes | last_logical_io_writes | min_logical_io_writes | max_logical_io_writes | stdev_logical_io_writes |
avg_physical_io_reads | last_physical_io_reads | min_physical_io_reads | max_physical_io_reads | stdev_physical_io_reads |
avg_clr_time | last_clr_time | min_clr_time | max_clr_time | stdev_clr_time |
avg_dop | last_dop | min_dop | max_dop | stdev_dop |
avg_query_max_used_memory | last_query_max_used_memory | min_query_max_used_memory | max_query_max_used_memory | stdev_query_max_used_memory |
avg_rowcount | last_rowcount | min_rowcount | max_rowcount | stdev_rowcount |
Kolumny w sys.query_store_runtime_stats
Te dane są przechwytywane tylko po zakończeniu wykonywania zapytania. Magazyn zapytań uwzględnia również SET
zapytania opcje, które mogą mieć wpływ na wybór planu wykonania, ponieważ wpływają na takie rzeczy, jak wyniki oceny wyrażeń stałych podczas procesu optymalizacji. Omówiłem ten temat w poprzednim poście.
Wniosek
To z pewnością będzie świetna funkcja i coś, co chciałbym wypróbować tak szybko, jak to możliwe (swoją drogą, demo Conora pokazuje „SQL Server 15 CTP1”, ale te bity nie są publicznie dostępne). Magazyn zapytań może być przydatny w przypadku uaktualnień, które mogą dotyczyć wersji CU, dodatku Service Pack lub programu SQL Server, ponieważ można analizować informacje zebrane przez magazyn zapytań przed i po, aby sprawdzić, czy jakiekolwiek zapytanie nie zostało wycofane. (A jeśli ta funkcja jest dostępna w niższych wersjach, możesz to zrobić nawet w scenariuszu aktualizacji SKU). Wiedza o tym może pomóc w podjęciu określonych działań w zależności od problemu, a jednym z tych rozwiązań może być wymuszenie poprzedniego planu jak wyjaśniono wcześniej.