Posts tagged DMV

[PL] Denali CTP3 – Nowe lepsze DBCC IND?

VN:F [1.7.9_1023]
Rating: 0.0/5 (0 votes cast)

Niedawno ukazała się nowa publiczna wersja Community Preview 3 (CTP3) systemu SQL Server vNext (codename Denali). Okoliczności ukazania się tej wersji były dość ciekawe, ponieważ wersja ukazała się dość niespodziewanie szybciej, niż ktokolwiek mógł podejrzewać. Jednocześnie firma Microsoft zarzuciła użytkowników bogactwem nowych wersji SQL Server 2008 R2 (Service Pack1) i 2008 (kilka Cumulative Update’ów). Jest więc co eksplorować, choć zalecam ostrożność, ponieważ z zaufanych źródeł wiem, że zwłaszcza Service Pack 1 do R2 jest źródłem licznych problemów (włącznie z tym, że dość trudno go poprawnie zainstalować).

Dopiero kilka dni temu znalazłem czas, by sprokurować sobie maszynę wirtualną do Denali CTP3. Maszyna działa pod kontrolą Windows Server 2008 SP1. Do tego trzeba było doinstalować parę rzeczy, ale na szczęście instalator wszystko dość jasno opisuje i nie ma problemów ze znalezieniem w sieci brakujących dodatków do systemu operacyjnego.

Jedną z pierwszych czynności po zainstalowaniu każdej nowej wersji SQL Servera jest w moim przypadku sprawdzenie, czy nie pojawiły się nowe widoki i funkcje dynamiczne. Uruchamiam zatem zapytanie:

SELECT 'sys.' + name
FROM sys.system_objects
WHERE [schema_id] = 4 AND name LIKE 'dm[_]%';

Przejrzenie listy w przypadku Denali CTP3 zaowocowało znalezieniem kilku ciekawych obiektów, ale najciekawszym z mojego punktu widzenia wydaje się być sys.dm_db_database_page_allocations. Jest to funkcja dynamiczna, która przyjmuje sporo parametrów: identyfikator bazy, identyfikator tabeli, identyfikator indeksu, numer partycji oraz rodzaj widoku. Lista parametrów przypomina widok sys.dm_db_index_physical_stats. Jednak nowa funkcja zwraca informacje prawie takie same, jakie dotąd można było uzyskać za pomocą polecenia DBCC IND. Możemy zatem obejrzeć, które strony wchodzą w skład konkretnego indeksu czy sprawdzić, z ilu poziomów stron dany indeks jest złożony. Przykładowe odwołanie do tej funkcji:

SELECT *
FROM sys.dm_db_database_page_allocations(
  DB_ID(),
  NULL,
  NULL,
  NULL,
  'DETAILED'
);

Przykładowy wynik (lista stron zaalokowanych dla całej bazy, widok o największej liczbie detali):

Nie muszę tłumaczyć, o ile lepiej byłoby mieć w systemie widok dynamiczny, na dodatek w pełni wspierany i udokumentowany. Do szczęścia jeszcze poproszę jakiś oficjalny zamiennik dla DBCC PAGE :-)

[PL] SQL Server – Czy potrzebujemy master.dbo.sysprocesses?

VN:F [1.7.9_1023]
Rating: 5.0/5 (1 vote cast)

Na portalu connect,microsoft,com jednym ze zgłoszonych błędów jest ten zgłoszony przez Tony’ego Rogersona pt. Deprecation of sysprocesses – DMV’s doesn’t fully replace all columns. Od momentu, gdy w dokumentacji SQL Servera w opisie widoku sysprocesses (tak, to jest widok, ale piszą o nim, jakby to była tabela, jak za czasów SQL Servera 2000) pojawił się zapisek:

This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.

rozgorzały dyskusje na temat słuszności posunięcia Microsoftu zmierzającego w kierunku wycięcia sysprocesses z przyszłych wersji SQL Servera. Głównym zarzutem zawsze było to, że widoki DMV, które Microsoft rekomenduje zamiast sysprocesses (konkretnie są to: sys.dm_exec_connections, sys.dm_exec_sessions, sys.dm_exec_requests) nie umożliwiają zwrócenia tych samych informacji, które można uzyskać odpytując sysprocesses. W szczególności nie można z ich pomocą dowiedzieć się, jakie sesje są podłączone do konkretnej bazy danych (np. w celu zamknięcia określonych połączeń poleceniem KILL), ponieważ nawet, jeśli w którymś z nich (sys.dm_exec_requests) pojawia się kolumna zawierająca identyfikator bazy danych, to niestety sensowne identyfikatory pojawiają się w niej tylko, gdy użytkownik używa obiektu proceduralnego, a nie pojawiają się w przypadku używania zapytań ad-hoc. Smaczku sprawie dodaje fakt, że Microsoft sam nadal wykorzystuje widok sysprocesses w zapytaniach zadawanych przez narzędzia najnowszych nawet wersji SQL Servera (np. Activity Monitor w SSMS 2008 R2 używa tego widoku do uzyskiwania listy sesji).

Paul White (aka SQLKiwi), świeżo upieczony SQL Server MVP i posiadacz arcyciekawego bloga (polecam!), podał obejście problemu z uzyskaniem przy użyciu DMV listy sesji podłączonych do konkretnej bazy danych:

SELECT request_session_id
FROM sys.dm_tran_locks
WHERE resource_type = N'DATABASE'
AND request_mode = N'S'
AND request_status = N'GRANT'
AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE'
AND resource_database_id = DB_ID(N'AdventureWorks');

Czy powyższe zapytanie zawsze zadziała poprawnie? Dla baz użytkownika, wg wszelkich przesłanek, tak. Testowałem różne warianty, poziomy izolacji i zapytanie zaproponowane przez Paula daje dobry wynik. Oczywiście, ciśnie się na usta pytanie, czemu nie można tego wyłuskać za pomocą trzech wspomnianych DMVs z rodziny sys.dm_exec_*. To pytanie do Microsoftu, na które chyba nikt w Redmond nie potrafi sensownie odpowiedzieć :-)

Analogiczne zapytanie z użyciem sysprocesses zwracające listę sesji podłączonych do bazy danych:

SELECT spid
FROM master.dbo.sysprocesses WITH (NOLOCK) -- asekuracyjny NOLOCK
WHERE spid > 50 -- choć ponoć spid > 50 nie zawsze oznacza sesję użytkownika
AND dbid = DB_ID(N'AdventureWorks');

A teraz zagadka na długi weekend. Dla jakich baz zapytanie Paula nie powie prawdy (nie pokaże pełnej listy podłączonych sesji, bo nie wykryje blokad typu SHARED_TRANSACTION_WORKSPACE)? Odpowiedzi możecie wpisywać w komentarzach do tego wpisu. Podpowiem, że akurat w przypadku tych baz raczej nikomu nie przyjdzie do głowy wycinać podłączonych sesji.

Miłego długiego majowego weekendu życzę :-)

[PL] SQL Server dla DBA – sys.dm_os_performance_counters

VN:F [1.7.9_1023]
Rating: 5.0/5 (2 votes cast)

W komentarzach do pierwszego wpisu z serii SQL Server dla DBA Robert Kubalski przypomniał o istnieniu widoku sys.dm_os_performance_counters, który może być źródłem cennych informacji o instancji SQL Server i bazach danych istniejących w ramach owej instancji. Pomyślałem, że warto by było napisać, w jaki sposób DBA może interpretować wartości zwracane w wyniku zapytania do wspomnianego widoku.

Pierwsze podejście – typy liczników

Widok dynamiczny sys.dm_os_performance_counters umożliwia podejrzenie wartości liczników monitora wydajności (perfmon.exe) dedykowanych konkretnej instancji SQL Server (tej, z której zadajemy zapytanie do widoku). Jednak nie wszystkie wartości liczbowe można bezpośrednio interpretować. Aby dowiedzieć, w jaki sposób należy interpretować wartości zwracane dla poszczególnych liczników, trzeba poznać typy liczników.

Istnieje kilka typów liczników (są to typy liczników WMI), a listę ich kodów można uzyskać w prosty sposób:

SELECT DISTINCT cntr_type
FROM sys.dm_os_performance_counters
ORDER BY cntr_type;

Oto owe typy liczników i ich interpretacja:

  • 65792 - PERF_COUNTER_LARGE_RAWCOUNT – obrazuje ostatnio przechwyconą wartość licznika; tego typu liczniki interpretujemy bezpośrednio – odczytana wartość może być od razu interpretowana (bez przeliczania)
  • 272696576 - PERF_COUNTER_BULK_COUNT – oznacza licznik, którego wartości są liczone per zadany interwał czasowy; do wyliczenia sensownej wartości takiego potrzebne są dwa pomiary (a następnie różnicę między pomiarami należy podzielić przez ilość jednostek czasu, np. ilość sekund)
  • 537003264PERF_LARGE_RAW_FRACTION – taki licznik używany jest do obliczenia ilorazu reprezentującego wskaźnik procentowy (jest podstawiany w liczniku dzielenia, a więc do pełni szczęścia potrzebujemy mianownika – patrz typ PERF_LARGE_RAW_BASE poniżej); niektóre liczniki (np. Buffer Cache Hit Ratio) są reprezentowane jako wartości procentowe i powstają jako wynik dzielenia licznika typu 537003264 przez licznik typu 1073939712
  • 1073874176 - PERF_AVERAGE_BULK – ten licznik jest używany do obliczenia ilorazu reprezentującego średnią wartość(podstawiany w liczniku dzielenia – znów potrzebny jest mianownik w postaci licznika typu PERF_LARGE_RAW_BASE); niektóre liczniki (np. Average Wait Time (ms)) reprezentują wartości średnie i powstają jako wynik dzielenia wartości licznika typu 1073874176 przez wartości odpowiedniego licznika typu 1073939712
  • 1073939712 - PERF_LARGE_RAW_BASE – licznik używany do obliczenia ilorazu (podstawiany w mianowniku dzielenia); stanowi parę z licznikiem typu 537003264 lub 1073874176.

A zatem, jeśli zobaczysz takie dwa liczniki:

image

znając typy liczników możesz wywnioskować, że należy podzielić wartość z kolumny cntr_value dla licznika Buffer cache hit ratio przez wartość z tej samej kolumny dla licznika Buffer cache hit ratio base (w tym konkretnym przypadku otrzymujemy wartość 1, co oznacza, że instancja notuje idealnie 100% trafień w bufor danych).

Drugie podejście – licznik, obiekt, instancja

Liczniki są podzielone pomiędzy obiekty. Obiekt można traktować jak kategorię. Oczywiście, są to te same obiekty, które instancja SQL Server dodaje do listy obiektów do użycia w monitorze wydajności. I jednocześnie trzeba pamiętać, że widok sys.dm_os_performance_counters zwraca wyłącznie wartości tych liczników, które pochodzą od danej instancji, na której wykonujemy zapytanie. Dla niektórych liczników, tak jak w perfmon.exe istnieje wiele instancji. Przykładem mogą być liczniki mówiące o rozmiarze dzienników transakcji w bazach danych oraz ilości miejsca zajętego w każdym z dzienników transakcji:

SELECT *
FROM sys.dm_os_performance_counters
WHERE counter_name LIKE '%Log File%';

image

Trzecie podejście – przykładowe zapytania i liczniki

O ile zapytanie o wszystkie liczniki nie obciąża praktycznie serwera (liczba odczytów i zużycie procesora są niemal zerowe, a sam widok zwraca co najwyżej kilka tysięcy wierszy – liczba wierszy zależy od ilości baz danych na instancji), o tyle zazwyczaj interesuje nas konkretny licznik lub grupa liczników.

Page Life Expectancy

Page Life Expectancy z obiektu Buffer Manager czyli czas życia stron w pamięci mierzony w sekundach. Ten licznik przydaje się, by zweryfikować, czy przypadkiem strony danych z pamięci nie są zrzucane do pliku stronicowania. Gwałtowny spadek tego licznika zazwyczaj mówi o opróżnieniu bufora danych – czy to celowym, czy wymuszonym przez system (prosty sposób na stwierdzenie braku ustawionego uprawnienia Lock pages in memory).

SELECT
  object_name,
  counter_name,
  cntr_value
FROM sys.dm_os_performance_counters
WHERE [object_name] LIKE '%Buffer Manager%'
AND counter_name = 'Page Life Expectancy';

Przykładowy wynik (niski, bo zmierzony tuż po restarcie usługi):

image

Przy okazji warto zauważyć, że kolumny tekstowe widoku sys,dm_os_performance_counters są typu nchar(128), a więc nazwy obiektów, liczników oraz instancji są dopełniane do 128 znaków spacjami. Jest to istotna sprawa przy pisaniu zapytań, zwłaszcza z użyciem operatora LIKE (warto dokładać znak % na końcu wzorca, by nie nadziać się na pułapkę związaną z dodatkowymi spacjami w nazwach).

Buffer cache hit ratio

Buffer cache hit ratio z obiektu Buffer Manager czyli procent trafień zapytań w strony znajdujące się w buforze danych. Im bliżej wartości 1 (oznaczającej 100%), tym lepiej.

SELECT
  c.object_name,
  c.counter_name,
  CASE
    WHEN b.cntr_value = 0 THEN 0
    ELSE CONVERT(numeric(38,2), c.cntr_value * 1.0 / b.cntr_value)
  END AS value
FROM sys.dm_os_performance_counters AS c
INNER JOIN sys.dm_os_performance_counters AS b
ON c.object_name = b.object_name
AND b.counter_name LIKE RTRIM(c.counter_name) + '%'
AND c.instance_name = b.instance_name
AND b.cntr_type = 1073939712
WHERE c.[object_name] LIKE '%Buffer Manager%'
AND c.counter_name = 'Buffer cache hit ratio';

Przykładowy wynik:

image

Powyższą technikę odszukiwania licznika i mianownika do obliczania ilorazu można stosować do większości liczników, których wartości wyliczamy z ilorazu. Są jednak przypadki, kiedy nazwa licznika i nazwa współczynnika używanego w mianowniku ilorazu różnią się nie tylko słowem “Base”. Przykładem może być licznik Avg. Time Between Batches (ms) z obiektu Broker TO Statistics:

image

Połączenia i aktywne transakcje

Liczniki Active Transactions z obiektu Databases oraz User Connections z obiektu General statistics pozwalają zorientować się, jaka jest aktualna liczba połączeń do instancji SQL Server oraz ile aktywnych transakcji jest otwartych w kontekście każdej bazy danych.

SELECT
  [object_name],
  counter_name,
  instance_name,
  cntr_value
FROM sys.dm_os_performance_counters
WHERE counter_name IN (
'Active Transactions',
'User Connections'
);

Przykładowy wynik:

image

Podsumowanie

Widok sys.dm_os_performance_counters daje DBA możliwość śledzenie pokaźnej ilości liczników mówiących wiele o kondycji instancji SQL Server. Co ważne, administrator nie musi korzystać z żadnych zewnętrznych narzędzi. Może wykorzystać widok do zbierania danych wydajnościowych do celów analizy, budowania tzw. baseline, klasycznego monitorowania, itd.

Widok ten jest szeroko wykorzystywany przez różne narzędzia firm trzecich (np. Quest Spotlight), jak również przez narzędzia dostępne w SQL Server (np. Performance Studio). Warto się nim zainteresować, zwłaszcza, jeśli naszym celem jest zbudowanie własnego rozwiązania do monitorowania serwera (patrz także wpis pt. SQL Server – Interaktywny performance dashboard dla ubogich).

[PL] SQL Server 2008 – Statystyki procedur i wyzwalaczy

VN:F [1.7.9_1023]
Rating: 0.0/5 (0 votes cast)

Geneza

Niedawno na forum portalu WSS.pl użytkownik miscu zapytał, w jaki sposób znaleźć datę ostatniego wykonania procedury składowanej na SQL Server 2005. Odpowiedziałem wówczas na jego pytanie, ale potem sprawdziłem, czy w SQL Server 2008 nie dałoby się uzyskać tej informacji nieco łatwiej, bez “grzebania” w kilku widokach i wykonywania podejrzanych złączeń w nadziei, że otrzymany wynik będzie choć trochę przedstawiał prawdę prawdziwą. I owszem, można.

Statystyki procedur

W SQL Server 2008 (i oczywiście w R2 także) dostajemy ciekawe widoki DMV – sys.dm_exec_procedure_stats i sys.dm_exec_trigger_stats. Widoki te pokazują statystyki wykonania odpowiednio procedur składowanych i wyzwalaczy. Oba widoki są widokami globalnymi, tzn. przechowują statystyki dla wszystkich baz danych naraz (nawet dla bazy mssqlresource coś tam się znajdzie). Oba widoki bazują na danych zebranych od ostatniego uruchomienia instancji SQL Server i bazują na tym, co siedzi w cache’u planów wykonania. Napisałem kawałek kodu (pewnie nie ja pierwszy), który wybiera co ciekawsze dane dotyczące procedur składowanych:

SELECT
  DB_NAME(s.database_id) AS [database_name],
  QUOTENAME(OBJECT_SCHEMA_NAME(s.[object_id], s.database_id)) +
  '.' +
  QUOTENAME(OBJECT_NAME(s.[object_id], s.database_id)) AS [procedure_name],
  s.cached_time,
  s.last_execution_time,
  s.execution_count,
  CONVERT(
    decimal(38,2),
    (s.execution_count * 1.0 / t.uptime)
  ) AS executions_per_minute,
  CONVERT(
    decimal(38,2),
    (s.max_elapsed_time * 1.0 / 1000)
  ) AS max_execution_time_miliseconds,
  CONVERT(
    decimal(38,2),
    ((s.total_elapsed_time * 1.0 / 1000) / s.execution_count)
  ) AS avg_execution_time_miliseconds
FROM sys.dm_exec_procedure_stats AS s
CROSS JOIN (
  SELECT
    DATEDIFF(minute, sqlserver_start_time, GETDATE()) AS uptime
  FROM sys.dm_os_sys_info
) AS t
WHERE s.database_id <> 32767;

Krótki komentarz do kodu:

  • wyświetlane dane zawierają:
    • database_name – nazwę bazy danych, w której znajduje się procedura,
    • procedure_name - dwuczłonową nazwę procedury,
    • cached_time – datę zapisania planu procedury w cache’u,
    • last_execution_time – datę ostatniego wykonania procedury,
    • execution_count – ilość wykonań procedury od ostatniego restartu usługi SQL Servera,
    • executions_count_per_minute – ilość wykonań procedury na minutę od ostatniego restartu usługi SQL Servera,
    • max_execution_time_miliseconds – maksymalny czas wykonania procedury wyrażony w milisekundach,
    • avg_execution_time_miliseconds – średni czas wykonania procedury wyrażony w milisekundach.
  • wszystkie czasy w widoku sys.dm_exec_procedure_stats są wyrażone w mikrosekundach, stąd operacje dzielenia przez 1000,
  • datę startu instancji wyciągam z widoku DMV sys.dm_os_sys_info (polecam do niego zajrzeć, bo w jednym wierszu zawiera sporo ciekawych informacji),
  • w klauzuli WHERE odfiltrowuję obiekty z ukrytej bazy systemowej mssqlresource, bo i tak na nic nam informacje o procedurach z tej bazy :-)

Zamiast filtru eliminującego obiekty z mssqlresource, można pokusić się o filtrowanie względem bazy, w której chcemy optymalizować procedury:

… WHERE s.database_id = DB_ID('MojaBazaDanych');

Przykładowy fragment wyniku powyższego zapytania:

image

Znajdź nieużywane procedury

Widok sys.dm_exec_procedure_stats może się też przydać w scenariuszu, w którym w bazie danych zawierającą dużą ilość procedur chcemy odnaleźć te procedury, które nie są wykorzystywane (nie zostały użyte od ostatniego uruchomienia serwera). Do tego celu można użyć na przykład takiego zapytania (tu – szukam procedur nieużywanych w bazie AdventureWorks2008R2):

USE AdventureWorks2008R2; -- tu wstaw nazwę Twojej bazy danych
GO
SELECT
  QUOTENAME(SCHEMA_NAME(p.[schema_id])) +
  '.' +
  QUOTENAME(p.name) AS unused_procedure
FROM sys.procedures AS p
INNER JOIN sys.sql_modules AS m
ON p.[object_id] = m.[object_id]
LEFT JOIN sys.dm_exec_procedure_stats AS s
ON s.database_id = DB_ID() AND p.[object_id] = s.[object_id]
WHERE s.[object_id] IS NULL AND m.is_recompiled = 0;
GO

Jeżeli serwer nie był restartowany przez odpowiednio długi czas i wiesz, że zostały przeprowadzone przypadki biznesowe wykorzystujące procedury, możesz założyć, że procedury wylistowane przez powyższe zapytanie wymagają sprawdzenia, czy są do czegokolwiek potrzebne (od polityki firmy i solidności programistów / administratorów zależy, jak często zdarzy się, że ktoś założy na bazie produkcyjnej tymczasowe obiekty, a następnie zapomni po sobie posprzątać). Celowo w powyższym zapytaniu sięgam do widoku sys.sql_modules, gdyż jest tam informacja o tym, czy procedura została utworzona z opcją WITH RECOMPILE (kolumna is_recompiled). A jeśli tak jest, jej planu nie znajdziesz w cache’u i nie możesz się sugerować jej brakiem w widoku sys.dm_exec_procedure_stats.

Słowo o wyzwalaczach

Analogiczne informacje można uzyskać także dla wyzwalaczy. I to nie tylko dla wyzwalaczy DML, ale także DDL (w tym dla logon triggerów). Do wykorzystania oprócz DMV sys.dm_exec_trigger_stats są widoki:

  • sys.triggers – zwraca metadane wyzwalaczy na poziomie bieżącej bazy danych (DML i DDL),
  • sys.server_triggers – zwraca metadane wyzwalaczy DDL na poziomie serwera (w tym logon triggerów).

[PL] SQL Server 2008 – DMV i sztuka optymalizacji

VN:F [1.7.9_1023]
Rating: 5.0/5 (2 votes cast)

SQL Server od wersji 2005 to Wielki Kolekcjoner. Zbiera liczne dane, z których wprawiony DBA może odczytać naprawdę wiele. Także w zakresie trudnej sztuki optymalizacji SQL Server może być naszym przyjacielem (choć bywa też naszym zaciekłym przeciwnikiem…).

W ostatnim czasie miałem możliwość zastosowania wszechobecnych w SQL Server 2008 widoków i funkcji dynamicznych (DMV/DMF) w procesie optymalizacji bazy danych. Jednym z zadań było odnajdowanie “podejrzanych” operacji w obiektach sporej bazy danych. W tym celu napisałem kawałek kodu T-SQL, który wyglądał mniej więcej tak:

USE master;

GO

IF OBJECT_ID('dbo.sp_querystats', 'V') IS NOT NULL

  DROP VIEW dbo.sp_querystats;

GO

CREATE VIEW dbo.sp_querystats

AS

SELECT

  DB_NAME(st.dbid) AS [database_name],

  QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid)) + '.' +

  QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)) AS [object_name],

  SUBSTRING(

    st.text,

    (qs.statement_start_offset/2)+1,

    (CASE qs.statement_end_offset

      WHEN -1 THEN DATALENGTH(st.text)

      ELSE qs.statement_end_offset

    END - qs.statement_start_offset)/2 + 1

  ) AS statement_text,

  qs.execution_count,

  qs.creation_time,

  qs.last_execution_time,

  (qs.total_logical_reads + qs.total_physical_reads) / qs.execution_count AS avg_reads,

  qs.total_logical_reads + qs.total_physical_reads AS total_reads,

  qs.max_logical_reads + qs.max_physical_reads AS max_reads,

  qs.min_logical_reads + qs.min_physical_reads AS min_reads,

  qs.max_logical_reads,

  qs.total_logical_reads,

  qs.total_physical_reads,

  qs.max_physical_reads,

  qs.total_elapsed_time / qs.execution_count AS avg_duration,

  qs.total_elapsed_time  AS total_duration,

  qs.max_elapsed_time  AS max_duration,

  qs.min_elapsed_time  AS min_duration,

  qs.total_worker_time / qs.execution_count AS avg_cpu,

  qs.total_worker_time AS total_cpu,

  qs.max_worker_time AS max_cpu,

  qs.min_worker_time AS min_cpu,

  pl.query_plan

FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK)

CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st

OUTER APPLY sys.dm_exec_query_plan(qs.plan_handle) AS pl;

GO

Widok sp_querystats posłużył mi do odpytywania danych dotyczących wydajności zapytań kolekcjonowanych przez SQL Server 2008. Krótki komentarz do kodu widoku:

  • Dzięki użyciu widoku sys.dm_exec_query_stats (dane z tego widoku są wyrzucane przy każdym uruchomieniu usługi SQL Server) wydobywam informacje o czasie trwania, zużyciu procesora, operacjach I/O (logicznych i fizycznych) – to są najczęstsze kryteria wyszukiwania problemów optymalizacyjnych.
  • Funkcja sys.dm_exec_sql_text umożliwia wydobycie takich informacji, jak nazwa bazy danych obiektu, z którego pochodziła składnia wychwycona przez SQL Server, nazwa samego obiektu oraz kod T-SQL fragmentu obiektu
  • Funkcja sys.dm_exec_query_plan daje wgląd w graficzny plan wykonania całego obiektu (lub zapytania – jeżeli to zapytanie ad-hoc).
  • Dzięki odpowiedniemu zastosowaniu funkcji systemowych OBJECT_NAME i OBJECT_SCHEMA_NAME (warto zwrócić uwagę, że funkcje te mogą przyjmować dwa parametry – drugim może być identyfikator bazy danych), uzyskuję pełne nazwy obiektów z wszystkich baz danych.
  • Widok ma w nazwie prefiks sp_ i jest założony w bazie master, by można się do niego odwołać z dowolnej bazy danych na instancji SQL Server.

Co mogę osiągnąć dzięki takiemu widokowi?

  • Mogę znajdować zapytania, które miały najsłabsze czasy wykonania, najwyższe zużycie procesora czy dokonały największej ilości odczytów z bazy danych. Przykład (najdłuższy średni czas wykonania):
SELECT TOP 50 * FROM sp_querystats ORDER BY avg_duration DESC;

  • Mogę sprawdzić, które zapytania wykonują się z dużym rozrzutem wymienionych powyżej kryteriów, co może świadczyć na przykład o rozmnożonych planach wykonania procedury składowanej. Na przykład: gdzie minimalny czas wykonania znacznie różni się od czasu maksymalnego:
SELECT TOP 50 * FROM sp_querystats ORDER BY (max_duration - min_duration) DESC;

  • Jakie składnie z danego obiektu (widoku, procedury, funkcji) siały największe spustoszenie na serwerze. Stosuję taką technikę, gdy uda mi się zgrubnie Profilerem “złapać” wywołanie felernego obiektu (zazwyczaj procedury lub funkcji). Na przykład: która składnia w procedurze spowodowała największe obciążenie procesora:
SELECT * FROM sp_querystats

WHERE st.objectid = OBJECT_ID(N'dbo.MojaProcedura')

ORDER BY avg_cpu DESC

  • Mogę podejrzeć plan wykonania (dla obiektów proceduralnych wyświetlane są plany wykonania wszystkich składni zawartych w obiekcie). Wystarczy kliknąć na interesującym nas rekordzie w kolumnie query_plan (oczywiście jeżeli w Management Studio wynik wyświetlamy w siatce, a nie w postaci tekstowej).
  • Mogę przeszukać plany wykonania zapisane w formacie XML w kolumnie query_plan i znaleźć niepokojące operatory (skany, niesłuszne ideowo typy złączeń, wyszukiwania z predykatami, opóźnione filtrowania, spoole itd.) czy podpowiedzi SQL Servera dotyczące brakujących indeksów (o analizie planów wykonania w formacie XML napiszę innym razem, bo to temat na spory artykuł).
  • Mogę sprawdzić, ile razy każda składnia była wykorzystana (i na przykład zweryfikować, jaki przebieg w procedurach mają instrukcje sterujące IF lub ocenić, czy jakaś składnia T-SQL nie powoduje masowego wywołania funkcji skalarnej). Na wartości z kolumny execution_count warto zwracać uwagę także, gdy zabieramy się do optymalizacji – czasem nie warto brać w swoje ręce obiektów, które są używane raz na kilka miesięcy…

Widok sp_querystats daje mi pogląd na wiele spraw. Przechwytując w procesie optymalizacji informacje dostarczone przez ślady (SQL Trace i Profiler) mogę niemal “od ręki” odnaleźć składnie wykonywane w ramach podejrzanego obiektu i zobaczyć agregację wszystkich wykonań tych poleceń. Czasem jest to wystarczający bodziec do podjęcia działań mających na celu dokonanie optymalizacji konkretnego zapytania. Polecam używanie DMV jako uzupełnienia dla wspomnianego SQL Trace i ewentualnych innych narzędzi wykorzystywanych do optymalizacji. Używajmy T-SQL do monitorowania T-SQL :-)

[PL] Materiały z prezentacji "DMV od A do Z"

VN:F [1.7.9_1023]
Rating: 0.0/5 (0 votes cast)

Bardzo dziękuję tym, którzy dzisiaj cierpliwie wysłuchali (mimo późnej pory) mojej prezentacji “DMV od A do Z” w ramach 43. spotkania PLSSUG Warszawa. Mam nadzieję, że choć część zaprezentowanego kodu T-SQL będzie przydatna w codziennej pracy z SQL Serverem. Zgodnie z obietnicą publikuję na stronie zasobów materiały (skrypt) z mojej sesji.

PS. Gratulacje dla Pawła Krasowskiego za przełamanie wszelkich oporów i wewnętrznych obaw i zaprezentowanie sesji o hierarchiach, która wyzwoliła chęć do dyskusji (przynajmniej we mnie). Dobry początek, Pawle.

Pobierz materiały z prezentacji “DMV od A do Z” (SQL, 19 KB)