Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy:Azure SQL Database
Baza danych SQL w usłudze Fabric
Dynamiczne widoki zarządzania (DMV) można wykonywać zapytania za pośrednictwem Transact-SQL (T-SQL), aby monitorować wydajność obciążeń i diagnozować problemy z wydajnością, które mogą być spowodowane zablokowanymi lub długotrwałymi zapytaniami, wąskimi gardłami zasobów, nieoptymalnymi planami zapytań i nie tylko.
W przypadku graficznego monitorowania zasobów zapytań użyj magazynu zapytań.
Wskazówka
Wypróbuj Database Hub w Microsoft Fabric! Centrum baz danych:
- automatycznie wykrywa Twoje bazy danych w Azure, Microsoft Fabric, lokalnie oraz obsługiwanych środowiskach multicloud.
- Automatycznie zapewnia gotowe, konfigurowalne pulpity nawigacyjne, które można udostępniać.
- Automatycznie identyfikuje najważniejsze priorytety i rekomendacje w Twoich bazach danych, które powinieneś zbadać lub poprawić.
- jest całkowicie darmowa.
Więcej informacji można znaleźć w Database Hub w Microsoft Fabric.
Monitorowanie użycia zasobów
Użycie zasobów można monitorować na poziomie bazy danych przy użyciu następujących widoków DMV.
sys.dm_db_resource_stats
Ponieważ ten widok zawiera szczegółowe dane użycia zasobów, należy najpierw użyć sys.dm_db_resource_stats funkcji analizy bieżącego stanu lub rozwiązywania problemów. Na przykład to zapytanie pokazuje średnie i maksymalne użycie zasobów dla bieżącej bazy danych w ciągu ostatniej godziny:
SELECT DB_NAME() AS database_name,
AVG(avg_cpu_percent) AS 'Average CPU use in percent',
MAX(avg_cpu_percent) AS 'Maximum CPU use in percent',
AVG(avg_data_io_percent) AS 'Average data IO in percent',
MAX(avg_data_io_percent) AS 'Maximum data IO in percent',
AVG(avg_log_write_percent) AS 'Average log write use in percent',
MAX(avg_log_write_percent) AS 'Maximum log write use in percent',
AVG(avg_memory_usage_percent) AS 'Average memory use in percent',
MAX(avg_memory_usage_percent) AS 'Maximum memory use in percent',
MAX(max_worker_percent) AS 'Maximum worker use in percent'
FROM sys.dm_db_resource_stats;
Widok sys.dm_db_resource_stats pokazuje ostatnie dane użycia zasobów w stosunku do limitów rozmiaru obliczeniowego. Wartości procentowe wykorzystania procesora CPU, operacji we/wy danych, zapisów dziennika, wątków roboczych i pamięci względem limitu są rejestrowane w każdym 15-sekundowym przedziale i przechowywane przez około godzinę.
Aby zapoznać się z innymi przykładowymi zapytaniami, zobacz przykłady w sys.dm_db_resource_stats.
sys.resource_stats
Widok sys.resource_stats w master bazie danych zawiera dodatkowe informacje, które mogą ułatwić monitorowanie wydajności bazy danych w określonej warstwie usługi i rozmiarze obliczeniowym. Dane są zbierane co 5 minut i są przechowywane przez około 14 dni. Ten widok jest przydatny w przypadku długoterminowej analizy historycznej sposobu, w jaki baza danych korzysta z zasobów.
Na poniższym wykresie przedstawiono użycie zasobów procesora CPU dla bazy danych Premium z rozmiarem obliczeniowym P2 dla każdej godziny w tygodniu. Ten wykres rozpoczyna się w poniedziałek, pokazuje pięć dni roboczych, a następnie pokazuje weekend, gdy w aplikacji dzieje się znacznie mniej.
Na podstawie danych ta baza danych ma obecnie szczytowe obciążenie CPU wynoszące nieco ponad 50% w odniesieniu do warstwy obliczeniowej P2 (we wtorek w południe). Jeśli CPU jest dominującym czynnikiem w profilu wykorzystania zasobów aplikacji, możesz zdecydować, że P2 jest odpowiednim rozmiarem jednostki obliczeniowej, aby zagwarantować, że obciążenie zawsze zmieści się w dostępnych zasobach. Jeśli spodziewasz się, że aplikacja wzrośnie wraz z upływem czasu, dobrym pomysłem jest posiadanie dodatkowego buforu zasobów, aby aplikacja nigdy nie osiągnęła limitu poziomu wydajności. Jeśli zwiększysz rozmiar obliczeniowy, możesz uniknąć widocznych przez klienta błędów, które mogą wystąpić, gdy baza danych nie ma wystarczającej mocy do efektywnego przetwarzania żądań, szczególnie w środowiskach wrażliwych na opóźnienia.
W przypadku innych typów aplikacji można interpretować ten sam graf inaczej. Jeśli na przykład aplikacja próbuje przetwarzać dane listy płac każdego dnia i ma ten sam wykres, ten rodzaj modelu "zadania wsadowego" może być odpowiedni w przypadku rozmiaru obliczeniowego P1. Rozmiar obliczeniowy P1 ma 100 jednostek DTU w porównaniu z 200 jednostkami DTU w rozmiarze obliczeniowym P2. Rozmiar obliczeniowy P1 zapewnia połowę wydajności rozmiaru obliczeniowego P2. Dlatego 50 procent użycia procesora CPU w P2 jest równe 100 procent użycia procesora w P1. Jeśli aplikacja nie ma limitów czasu, może nie mieć znaczenia, czy zadanie trwa 2 godziny lub 2,5 godziny, jeśli zostanie wykonane dzisiaj. Aplikacja w tej kategorii prawdopodobnie może używać rozmiaru obliczeniowego P1. Możesz wykorzystać to, że w ciągu dnia są okresy niższego wykorzystania zasobów, dzięki czemu każdy „duży skok” może przesunąć się na jeden z późniejszych okresów niższego wykorzystania. Rozmiar obliczeniowy P1 może być odpowiedni dla tego rodzaju aplikacji (i zaoszczędzić pieniądze), o ile zadania mogą być wykonywane codziennie.
Silnik bazy danych udostępnia informacje o wykorzystaniu zasobów dla każdej aktywnej bazy danych w widoku sys.resource_stats bazy danych master na każdym serwerze logicznym. Dane w widoku są agregowane przez 5-minutowe interwały. Wyświetlenie tych danych w tabeli może potrwać kilka minut, więc sys.resource_stats jest bardziej przydatne w przypadku analizy historycznej, a nie analizy niemal w czasie rzeczywistym.
sys.resource_stats Wykonaj zapytanie względem widoku, aby wyświetlić najnowszą historię bazy danych i sprawdzić, czy wybrany rozmiar obliczeniowy dostarczył odpowiednią wydajność w razie potrzeby.
Uwaga
Aby wykonać zapytanie master w poniższych przykładach, musisz mieć połączenie z bazą sys.resource_stats danych.
W tym przykładzie przedstawiono dane w pliku sys.resource_stats:
SELECT TOP 10 *
FROM sys.resource_stats
WHERE database_name = 'userdb1'
ORDER BY start_time DESC;
W następnym przykładzie przedstawiono różne sposoby używania sys.resource_stats widoku wykazu w celu uzyskania informacji o sposobie korzystania z zasobów bazy danych:
Aby sprawdzić wykorzystanie zasobów z ostatniego tygodnia dla bazy danych użytkownika
userdb1, możesz uruchomić następujące zapytanie, podstawiając własną nazwę bazy danych:SELECT * FROM sys.resource_stats WHERE database_name = 'userdb1' AND start_time > DATEADD(day, -7, GETDATE()) ORDER BY start_time DESC;Aby ocenić, jak dobrze obciążenie pasuje do rozmiaru obliczeniowego, należy przejść do szczegółów poszczególnych aspektów metryk zasobów: procesora CPU, operacji we/wy danych, zapisu dziennika, liczby procesów roboczych i liczby sesji. Oto zmienione zapytanie używające
sys.resource_statsdo raportowania średnich i maksymalnych wartości tych metryk zasobów dla każdego rozmiaru mocy obliczeniowej, dla którego skonfigurowano bazę danych:SELECT rs.database_name, rs.sku, MAX(rs.storage_in_megabytes) AS storage_mb, AVG(rs.avg_cpu_percent) AS 'Average CPU Utilization In %', MAX(rs.avg_cpu_percent) AS 'Maximum CPU Utilization In %', AVG(rs.avg_data_io_percent) AS 'Average Data IO In %', MAX(rs.avg_data_io_percent) AS 'Maximum Data IO In %', AVG(rs.avg_log_write_percent) AS 'Average Log Write Utilization In %', MAX(rs.avg_log_write_percent) AS 'Maximum Log Write Utilization In %', MAX(rs.max_worker_percent) AS 'Maximum Requests In %', MAX(rs.max_session_percent) AS 'Maximum Sessions In %' FROM sys.resource_stats AS rs WHERE rs.database_name = 'userdb1' AND rs.start_time > DATEADD(day, -7, GETDATE()) GROUP BY rs.database_name, rs.sku;Dzięki tym informacjom o średnich i maksymalnych wartościach każdej metryki zasobów możesz ocenić, jak dobrze obciążenie pasuje do wybranego rozmiaru obliczeniowego. Zazwyczaj średnie wartości z
sys.resource_statsdają dobrą linię bazową do użycia względem rozmiaru docelowego.W przypadku baz danych w modelu zakupu DTU:
Na przykład możesz używać warstwy usługi Standard w rozmiarze obliczeniowym S2. Średnie wykorzystanie procesora CPU oraz średni procent operacji odczytu i zapisu we/wy są poniżej 40%, średnia liczba procesów roboczych jest niższa niż 50, a średnia liczba sesji jest niższa niż 200. Twoje obciążenie robocze może pasować do warstwy mocy obliczeniowej S1. Łatwo sprawdzić, czy baza danych mieści się w limitach procesów roboczych i sesji. Aby sprawdzić, czy baza danych mieści się w niższym rozmiarze obliczeniowym, podziel liczbę jednostek DTU mniejszego rozmiaru obliczeniowego na liczbę jednostek DTU bieżącego rozmiaru obliczeniowego, a następnie pomnoż wynik o 100:
S1 DTU / S2 DTU * 100 = 20 / 50 * 100 = 40Wynikiem jest względna różnica wydajności między dwoma rozmiarami obliczeniowymi w procentach. Jeśli użycie zasobu nie przekracza tej wartości procentowej, obciążenie może mieścić się w niższym rozmiarze obliczeniowym. Należy jednak przyjrzeć się wszystkim zakresom wartości użycia zasobów i określić, według wartości procentowych, jak często obciążenie bazy danych mieści się w niższym rozmiarze obliczeniowym. Następujące zapytanie zwraca wartość procentową dopasowania na wymiar zasobu na podstawie progu wynoszącego 40 procent obliczonego w tym przykładzie:
SELECT database_name, 100 * ((COUNT(database_name) - SUM(CASE WHEN avg_cpu_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'CPU Fit Percent', 100 * ((COUNT(database_name) - SUM(CASE WHEN avg_log_write_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Log Write Fit Percent', 100 * ((COUNT(database_name) - SUM(CASE WHEN avg_data_io_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Physical Data IO Fit Percent' FROM sys.resource_stats WHERE start_time > DATEADD(day, -7, GETDATE()) AND database_name = 'sample' --remove to see all databases GROUP BY database_name;Na podstawie warstwy usługi bazy danych możesz zdecydować, czy obciążenie mieści się w niższym rozmiarze obliczeniowym. Jeśli cel obciążenia bazy danych wynosi 99,9 procent, a poprzednie zapytanie zwraca wartości większe niż 99,9 procent dla wszystkich trzech wymiarów zasobów, obciążenie prawdopodobnie mieści się w niższym rozmiarze obliczeniowym.
Zapoznanie się z wartością procentową dopasowania daje również wgląd w to, czy należy przejść do następnego wyższego rozmiaru obliczeniowego w celu osiągnięcia celu. Na przykład użycie procesora CPU dla przykładowej bazy danych w ciągu ostatniego tygodnia:
Średnie użycie procesora CPU (%) Maksymalny procent procesora CPU 24.5 100.00 Średni procesor CPU wynosi około jednej czwartej limitu rozmiaru obliczeniowego, co dobrze pasuje do rozmiaru obliczeniowego bazy danych.
W przypadku baz danych w modelu zakupowym DTU i modelu zakupowym vCore:
Maksymalna wartość pokazuje, że baza danych osiąga limit rozmiaru obliczeniowego. Czy musisz przejść do następnego wyższego rozmiaru obliczeniowego? Sprawdź, ile razy obciążenie osiągnie 100 procent, a następnie porównaj je z celem obciążenia bazy danych.
SELECT database_name, 100 * ((COUNT(database_name) - SUM(CASE WHEN avg_cpu_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'CPU Fit Percent', 100 * ((COUNT(database_name) - SUM(CASE WHEN avg_log_write_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Log Write Fit Percent', 100 * ((COUNT(database_name) - SUM(CASE WHEN avg_data_io_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Physical Data IO Fit Percent' FROM sys.resource_stats WHERE start_time > DATEADD(day, -7, GETDATE()) AND database_name = 'sample' --remove to see all databases GROUP BY database_name;Te wartości procentowe oznaczają, jaki odsetek próbek przypadał na obciążenie mieszczące się w ramach bieżącego rozmiaru zasobów obliczeniowych. Jeśli to zapytanie zwróci wartość mniejszą niż 99,9 procent dla dowolnego z trzech wymiarów zasobów, średnie obciążenie próbki przekroczyło limity. Rozważ przejście do następnego wyższego rozmiaru obliczeniowego lub użycie technik dostrajania aplikacji w celu zmniejszenia obciążenia bazy danych.
sys.dm_elastic_pool_resource_stats
Dotyczy tylko:Azure SQL Database
Podobnie jak sys.dm_db_resource_stats, sys.dm_elastic_pool_resource_stats udostępnia ostatnie i szczegółowe dane dotyczące użycia zasobów elastycznej puli usługi Azure SQL Database. Do widoku można wysyłać zapytania z dowolnej bazy danych w puli elastycznej w celu uzyskania danych o użyciu zasobów dla całej puli, a nie dla konkretnej bazy danych. Wartości procentowe zgłaszane przez ten DMV odnoszą się do limitów puli elastycznej, które mogą być wyższe niż limity dla bazy danych należącej do tej puli.
W tym przykładzie przedstawiono podsumowane dane użycia zasobów dla bieżącej elastycznej puli w ciągu ostatnich 15 minut:
SELECT dso.elastic_pool_name,
AVG(eprs.avg_cpu_percent) AS avg_cpu_percent,
MAX(eprs.avg_cpu_percent) AS max_cpu_percent,
AVG(eprs.avg_data_io_percent) AS avg_data_io_percent,
MAX(eprs.avg_data_io_percent) AS max_data_io_percent,
AVG(eprs.avg_log_write_percent) AS avg_log_write_percent,
MAX(eprs.avg_log_write_percent) AS max_log_write_percent,
MAX(eprs.max_worker_percent) AS max_worker_percent,
MAX(eprs.used_storage_percent) AS max_used_storage_percent,
MAX(eprs.allocated_storage_percent) AS max_allocated_storage_percent
FROM sys.dm_elastic_pool_resource_stats AS eprs
CROSS JOIN sys.database_service_objectives AS dso
WHERE eprs.end_time >= DATEADD(minute, -15, GETUTCDATE())
GROUP BY dso.elastic_pool_name;
Jeśli okaże się, że każde użycie zasobów zbliża się do 100% przez dłuższy czas, może być konieczne przejrzenie użycia zasobów dla poszczególnych baz danych w tej samej elastycznej puli, aby określić, ile każda baza danych przyczynia się do użycia zasobów na poziomie puli.
sys.elastic_pool_resource_stats
Dotyczy tylko:Azure SQL Database
Podobnie jak sys.resource_stats, sys.elastic_pool_resource_stats w bazie danych master udostępnia historyczne dane o użyciu zasobów dla wszystkich pul elastycznych na serwerze logicznym. Za pomocą sys.elastic_pool_resource_stats można monitorować dane historyczne z ostatnich 14 dni, w tym analizować trendy użycia.
W tym przykładzie przedstawiono podsumowane dane użycia zasobów w ciągu ostatnich siedmiu dni dla wszystkich pul elastycznych na bieżącym serwerze logicznym. Wykonaj zapytanie w master bazie danych.
SELECT elastic_pool_name,
AVG(avg_cpu_percent) AS avg_cpu_percent,
MAX(avg_cpu_percent) AS max_cpu_percent,
AVG(avg_data_io_percent) AS avg_data_io_percent,
MAX(avg_data_io_percent) AS max_data_io_percent,
AVG(avg_log_write_percent) AS avg_log_write_percent,
MAX(avg_log_write_percent) AS max_log_write_percent,
MAX(max_worker_percent) AS max_worker_percent,
AVG(avg_storage_percent) AS avg_used_storage_percent,
MAX(avg_storage_percent) AS max_used_storage_percent,
AVG(avg_allocated_storage_percent) AS avg_allocated_storage_percent,
MAX(avg_allocated_storage_percent) AS max_allocated_storage_percent
FROM sys.elastic_pool_resource_stats
WHERE start_time >= DATEADD(day, -7, GETUTCDATE())
GROUP BY elastic_pool_name
ORDER BY elastic_pool_name ASC;
Żądania współbieżne
Aby wyświetlić bieżącą liczbę współbieżnych żądań, uruchom to zapytanie w bazie danych użytkownika:
SELECT COUNT(*) AS [Concurrent_Requests]
FROM sys.dm_exec_requests;
To tylko chwilowy obraz sytuacji w danym momencie. Aby lepiej zrozumieć wymagania dotyczące Twojego obciążenia i współbieżnych żądań, musisz zbierać wiele próbek na przestrzeni czasu.
Średnia szybkość żądań
W tym przykładzie pokazano, jak znaleźć średni współczynnik żądań dla bazy danych lub baz danych w elastycznej puli w danym okresie. W tym przykładzie okres jest ustawiony na 30 sekund. Można ją dostosować, modyfikując instrukcję WAITFOR DELAY . Wykonaj to zapytanie w bazie danych użytkownika. Jeśli baza danych znajduje się w elastycznej puli i jeśli masz wystarczające uprawnienia, wyniki obejmują inne bazy danych w elastycznej puli.
DECLARE @DbRequestSnapshot TABLE (
database_name sysname PRIMARY KEY,
total_request_count bigint NOT NULL,
snapshot_time datetime2 NOT NULL DEFAULT (SYSDATETIME())
);
INSERT INTO @DbRequestSnapshot
(
database_name,
total_request_count
)
SELECT rg.database_name,
wg.total_request_count
FROM sys.dm_resource_governor_workload_groups AS wg
INNER JOIN sys.dm_user_db_resource_governance AS rg
ON wg.name = CONCAT('UserPrimaryGroup.DBId', rg.database_id);
WAITFOR DELAY '00:00:30';
SELECT rg.database_name,
(wg.total_request_count - drs.total_request_count) / DATEDIFF(second, drs.snapshot_time, SYSDATETIME()) AS requests_per_second
FROM sys.dm_resource_governor_workload_groups AS wg
INNER JOIN sys.dm_user_db_resource_governance AS rg
ON wg.name = CONCAT('UserPrimaryGroup.DBId', rg.database_id)
INNER JOIN @DbRequestSnapshot AS drs
ON rg.database_name = drs.database_name;
Bieżące sesje
Aby wyświetlić liczbę bieżących aktywnych sesji, uruchom to zapytanie w bazie danych:
SELECT COUNT(*) AS [Sessions]
FROM sys.dm_exec_sessions
WHERE is_user_process = 1;
To zapytanie zwraca liczbę punktów w czasie. Jeśli z czasem zbierzesz wiele próbek, najlepiej zrozumiesz sposób korzystania z sesji.
Najnowsza historia żądań, sesji i procesów roboczych
Ten przykład zwraca niedawne dane historyczne dotyczące użycia żądań, sesji i wątków roboczych dla bazy danych lub baz danych należących do puli elastycznej. Każdy wiersz reprezentuje migawkę użycia zasobów w danym momencie dla bazy danych. Kolumna requests_per_second jest średnią szybkością żądań w przedziale czasu kończącym się na .snapshot_time Jeśli baza danych znajduje się w elastycznej puli i jeśli masz wystarczające uprawnienia, wyniki obejmują inne bazy danych w elastycznej puli.
SELECT rg.database_name,
wg.snapshot_time,
wg.active_request_count,
wg.active_worker_count,
wg.active_session_count,
CAST (wg.delta_request_count AS DECIMAL) / duration_ms * 1000 AS requests_per_second
FROM sys.dm_resource_governor_workload_groups_history_ex AS wg
INNER JOIN sys.dm_user_db_resource_governance AS rg
ON wg.name = CONCAT('UserPrimaryGroup.DBId', rg.database_id)
ORDER BY snapshot_time DESC;
Obliczanie rozmiarów baz danych i obiektów
Następujące zapytanie zwraca rozmiar danych w bazie danych (w megabajtach):
-- Calculates the size of the database.
SELECT SUM(CAST (FILEPROPERTY(name, 'SpaceUsed') AS BIGINT) * 8192.) / 1024 / 1024 AS size_mb
FROM sys.database_files
WHERE type_desc = 'ROWS';
Następujące zapytanie zwraca rozmiar pojedynczych obiektów (w megabajtach) w bazie danych:
-- Calculates the size of individual database objects.
SELECT o.name,
SUM(ps.reserved_page_count) * 8.0 / 1024 AS size_mb
FROM sys.dm_db_partition_stats AS ps
INNER JOIN sys.objects AS o
ON ps.object_id = o.object_id
GROUP BY o.name
ORDER BY size_mb DESC;
Identyfikowanie problemów z wydajnością procesora CPU
Ta sekcja ułatwia identyfikowanie poszczególnych zapytań, które są głównymi użytkownikami procesora CPU.
Wskazówka
Rozważ automatyczne dostrajanie bazy danych , aby automatycznie zwiększyć wydajność zapytań.
Jeśli użycie procesora CPU przekracza 80% przez dłuższy czas, rozważ następujące kroki rozwiązywania problemów, czy problem z procesorem CPU występuje teraz , czy wystąpił w przeszłości. Możesz również wykonać kroki opisane w tej sekcji, aby aktywnie identyfikować zapytania zużywające najwięcej procesora CPU i dostroić je. W niektórych przypadkach zmniejszenie użycia procesora może umożliwić zmniejszenie rozmiaru baz danych i pul elastycznych oraz obniżenie kosztów.
Kroki rozwiązywania problemów są takie same w przypadku autonomicznych baz danych i baz danych w elastycznej puli. Wykonaj wszystkie zapytania w bazie danych użytkownika.
Problem z CPU występuje obecnie
Jeśli problem występuje teraz, istnieją dwa możliwe scenariusze:
Wiele pojedynczych zapytań, które łącznie powodują wysokie użycie procesora CPU
Użyj następującego zapytania, aby zidentyfikować najważniejsze zapytania według skrótu zapytania:
PRINT '-- top 10 Active CPU Consuming Queries (aggregated)--';
SELECT TOP 10 GETDATE() AS runtime,
*
FROM (SELECT query_stats.query_hash,
SUM(query_stats.cpu_time) AS 'Total_Request_Cpu_Time_Ms',
SUM(logical_reads) AS 'Total_Request_Logical_Reads',
MIN(start_time) AS 'Earliest_Request_start_Time',
COUNT(*) AS 'Number_Of_Requests',
SUBSTRING(REPLACE(REPLACE(MIN(query_stats.statement_text), CHAR(10), ' '), CHAR(13), ' '), 1, 256) AS "Statement_Text"
FROM (SELECT req.*,
SUBSTRING(ST.text, (req.statement_start_offset / 2) + 1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH(ST.text) ELSE req.statement_end_offset END - req.statement_start_offset) / 2) + 1) AS statement_text
FROM sys.dm_exec_requests AS req
CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) AS ST) AS query_stats
GROUP BY query_hash) AS t
ORDER BY Total_Request_Cpu_Time_Ms DESC;
Długotrwałe zapytania, które zużywają procesor CPU, są nadal uruchomione
Użyj następującego zapytania, aby zidentyfikować te zapytania:
PRINT '--top 10 Active CPU Consuming Queries by sessions--';
SELECT TOP 10 req.session_id, req.start_time, cpu_time 'cpu_time_ms', OBJECT_NAME(ST.objectid, ST.dbid) 'ObjectName', SUBSTRING(REPLACE(REPLACE(SUBSTRING(ST.text, (req.statement_start_offset / 2)+1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH(ST.text)ELSE req.statement_end_offset END-req.statement_start_offset)/ 2)+1), CHAR(10), ' '), CHAR(13), ' '), 1, 512) AS statement_text
FROM sys.dm_exec_requests AS req
CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) AS ST
ORDER BY cpu_time DESC;
GO
Problem z CPU wystąpił wcześniej
Jeśli problem wystąpił w przeszłości i chcesz przeprowadzić analizę przyczyn źródłowych, użyj Query Store. Użytkownicy z dostępem do bazy danych mogą używać języka T-SQL do wykonywania zapytań dotyczących danych magazynu zapytań. Domyślnie magazyn zapytań przechwytuje zagregowane statystyki zapytań dla interwałów jednogodzinnych.
Użyj następującego zapytania, aby przyjrzeć się aktywności w przypadku zapytań zużywających wysokie użycie procesora CPU. To zapytanie zwraca 15 najważniejszych zapytań zużywających procesor CPU. Pamiętaj, aby zmienić
rsi.start_time >= DATEADD(hour, -2, GETUTCDATE(), aby wyświetlić okres inny niż ostatnie dwie godziny:-- Top 15 CPU consuming queries by query hash -- Note that a query hash can have many query ids if not parameterized or not parameterized properly WITH AggregatedCPU AS (SELECT q.query_hash, SUM(count_executions * avg_cpu_time / 1000.0) AS total_cpu_ms, SUM(count_executions * avg_cpu_time / 1000.0) / SUM(count_executions) AS avg_cpu_ms, MAX(rs.max_cpu_time / 1000.00) AS max_cpu_ms, MAX(max_logical_io_reads) AS max_logical_reads, COUNT(DISTINCT p.plan_id) AS number_of_distinct_plans, COUNT(DISTINCT p.query_id) AS number_of_distinct_query_ids, SUM(CASE WHEN rs.execution_type_desc = 'Aborted' THEN count_executions ELSE 0 END) AS Aborted_Execution_Count, SUM(CASE WHEN rs.execution_type_desc = 'Regular' THEN count_executions ELSE 0 END) AS Regular_Execution_Count, SUM(CASE WHEN rs.execution_type_desc = 'Exception' THEN count_executions ELSE 0 END) AS Exception_Execution_Count, SUM(count_executions) AS total_executions, MIN(qt.query_sql_text) AS sampled_query_text FROM sys.query_store_query_text AS qt INNER JOIN sys.query_store_query AS q ON qt.query_text_id = q.query_text_id INNER JOIN sys.query_store_plan AS p ON q.query_id = p.query_id INNER JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id = p.plan_id INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_id WHERE rs.execution_type_desc IN ('Regular', 'Aborted', 'Exception') AND rsi.start_time >= DATEADD(HOUR, -2, GETUTCDATE()) GROUP BY q.query_hash), OrderedCPU AS (SELECT query_hash, total_cpu_ms, avg_cpu_ms, max_cpu_ms, max_logical_reads, number_of_distinct_plans, number_of_distinct_query_ids, total_executions, Aborted_Execution_Count, Regular_Execution_Count, Exception_Execution_Count, sampled_query_text, ROW_NUMBER() OVER (ORDER BY total_cpu_ms DESC, query_hash ASC) AS query_hash_row_number FROM AggregatedCPU) SELECT OD.query_hash, OD.total_cpu_ms, OD.avg_cpu_ms, OD.max_cpu_ms, OD.max_logical_reads, OD.number_of_distinct_plans, OD.number_of_distinct_query_ids, OD.total_executions, OD.Aborted_Execution_Count, OD.Regular_Execution_Count, OD.Exception_Execution_Count, OD.sampled_query_text, OD.query_hash_row_number FROM OrderedCPU AS OD WHERE OD.query_hash_row_number <= 15 --get top 15 rows by total_cpu_ms ORDER BY total_cpu_ms DESC;Po zidentyfikowaniu problematycznych zapytań nadszedł czas, aby dostosować te zapytania w celu zmniejszenia wykorzystania procesora CPU. Alternatywnie możesz zwiększyć rozmiar obliczeniowy bazy danych lub elastycznej puli, aby obejść ten problem.
Aby uzyskać więcej informacji na temat obsługi problemów z wydajnością procesora CPU w usłudze Azure SQL Database, zobacz Diagnozowanie i rozwiązywanie problemów z wysokim użyciem procesora CPU w usłudze Azure SQL Database i bazie danych SQL w usłudze Microsoft Fabric.
Zidentyfikuj problemy z wydajnością I/O
Podczas identyfikowania problemów z wydajnością operacji wejścia/wyjścia (I/O) pamięci masowej główne typy oczekiwania to:
PAGEIOLATCH_*W przypadku problemów z operacjami wejścia/wyjścia pliku danych (w tym
PAGEIOLATCH_SH,PAGEIOLATCH_EX,PAGEIOLATCH_UP). Jeśli nazwa typu oczekiwania zawiera IO, wskazuje to na problem z operacjami wejścia/wyjścia. Jeśli w nazwie oczekiwania zatrzasku strony nie ma IO, wskazuje to na inny rodzaj problemu, który nie jest związany z wydajnością magazynu (na przykład rywalizacja).WRITE_LOGW przypadku problemów z we/wy dziennika transakcji.
Jeśli problem z wejściem/wyjściem występuje teraz
Użyj sys.dm_exec_requests lub sys.dm_os_waiting_tasks, aby wyświetlić element wait_type i wait_time.
Określ użycie wejścia/wyjścia danych i dziennika
Użyj następującego zapytania, aby określić użycie danych i operacji wejścia/wyjścia dziennika.
SELECT DB_NAME() AS database_name,
end_time AS UTC_time,
rs.avg_data_io_percent AS 'Data IO In % of Limit',
rs.avg_log_write_percent AS 'Log Write Utilization In % of Limit'
FROM sys.dm_db_resource_stats AS rs --past hour only
ORDER BY rs.end_time DESC;
Aby uzyskać więcej przykładów użycia sys.dm_db_resource_stats, zobacz sekcję Monitorowanie użycia zasobów w dalszej części tego artykułu.
Jeśli osiągnięto limit operacji we/wy, masz dwie opcje:
- Uaktualnij rozmiar obliczeniowy lub warstwę usługi
- Zidentyfikuj i dostrój zapytania generujące najwięcej operacji wejścia/wyjścia.
Wyświetlaj operacje wejścia/wyjścia związane z buforem za pomocą Query Store
Aby zidentyfikować zapytania z największą liczbą oczekiwań związanych z operacjami we/wy, możesz użyć następującego zapytania Query Store, aby wyświetlić ostatnie dwie godziny rejestrowanej aktywności:
-- Top queries that waited on buffer
-- Note these are finished queries
WITH Aggregated AS (SELECT q.query_hash, SUM(total_query_wait_time_ms) total_wait_time_ms, SUM(total_query_wait_time_ms / avg_query_wait_time_ms) AS total_executions, MIN(qt.query_sql_text) AS sampled_query_text, MIN(wait_category_desc) AS wait_category_desc
FROM sys.query_store_query_text AS qt
INNER JOIN sys.query_store_query AS q ON qt.query_text_id=q.query_text_id
INNER JOIN sys.query_store_plan AS p ON q.query_id=p.query_id
INNER JOIN sys.query_store_wait_stats AS waits ON waits.plan_id=p.plan_id
INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id=waits.runtime_stats_interval_id
WHERE wait_category_desc='Buffer IO' AND rsi.start_time>=DATEADD(HOUR, -2, GETUTCDATE())
GROUP BY q.query_hash), Ordered AS (SELECT query_hash, total_executions, total_wait_time_ms, sampled_query_text, wait_category_desc, ROW_NUMBER() OVER (ORDER BY total_wait_time_ms DESC, query_hash ASC) AS query_hash_row_number
FROM Aggregated)
SELECT OD.query_hash, OD.total_executions, OD.total_wait_time_ms, OD.sampled_query_text, OD.wait_category_desc, OD.query_hash_row_number
FROM Ordered AS OD
WHERE OD.query_hash_row_number <= 15 -- get top 15 rows by total_wait_time_ms
ORDER BY total_wait_time_ms DESC;
GO
Możesz również użyć widoku sys.query_store_runtime_stats , koncentrując się na zapytaniach z dużymi wartościami w kolumnach avg_physical_io_reads i avg_num_physical_io_reads .
Wyświetl łączną liczbę operacji wejścia/wyjścia dziennika dla oczekiwań WRITELOG
Jeśli typ oczekiwania to WRITELOG, użyj następującego zapytania, aby wyświetlić całkowitą liczbę operacji wejścia/wyjścia dziennika dla każdej instrukcji:
-- Top transaction log consumers
-- Adjust the time window by changing
-- rsi.start_time >= DATEADD(hour, -2, GETUTCDATE())
WITH AggregatedLogUsed
AS (SELECT q.query_hash,
SUM(count_executions * avg_cpu_time / 1000.0) AS total_cpu_ms,
SUM(count_executions * avg_cpu_time / 1000.0) / SUM(count_executions) AS avg_cpu_ms,
SUM(count_executions * avg_log_bytes_used) AS total_log_bytes_used,
MAX(rs.max_cpu_time / 1000.00) AS max_cpu_ms,
MAX(max_logical_io_reads) max_logical_reads,
COUNT(DISTINCT p.plan_id) AS number_of_distinct_plans,
COUNT(DISTINCT p.query_id) AS number_of_distinct_query_ids,
SUM( CASE
WHEN rs.execution_type_desc = 'Aborted' THEN
count_executions
ELSE 0
END
) AS Aborted_Execution_Count,
SUM( CASE
WHEN rs.execution_type_desc = 'Regular' THEN
count_executions
ELSE 0
END
) AS Regular_Execution_Count,
SUM( CASE
WHEN rs.execution_type_desc = 'Exception' THEN
count_executions
ELSE 0
END
) AS Exception_Execution_Count,
SUM(count_executions) AS total_executions,
MIN(qt.query_sql_text) AS sampled_query_text
FROM sys.query_store_query_text AS qt
INNER JOIN sys.query_store_query AS q ON qt.query_text_id = q.query_text_id
INNER JOIN sys.query_store_plan AS p ON q.query_id = p.query_id
INNER JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id = p.plan_id
INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_id
WHERE rs.execution_type_desc IN ( 'Regular', 'Aborted', 'Exception' )
AND rsi.start_time >= DATEADD(HOUR, -2, GETUTCDATE())
GROUP BY q.query_hash),
OrderedLogUsed
AS (SELECT query_hash,
total_log_bytes_used,
number_of_distinct_plans,
number_of_distinct_query_ids,
total_executions,
Aborted_Execution_Count,
Regular_Execution_Count,
Exception_Execution_Count,
sampled_query_text,
ROW_NUMBER() OVER (ORDER BY total_log_bytes_used DESC, query_hash ASC) AS query_hash_row_number
FROM AggregatedLogUsed)
SELECT OD.total_log_bytes_used,
OD.number_of_distinct_plans,
OD.number_of_distinct_query_ids,
OD.total_executions,
OD.Aborted_Execution_Count,
OD.Regular_Execution_Count,
OD.Exception_Execution_Count,
OD.sampled_query_text,
OD.query_hash_row_number
FROM OrderedLogUsed AS OD
WHERE OD.query_hash_row_number <= 15 -- get top 15 rows by total_log_bytes_used
ORDER BY total_log_bytes_used DESC;
GO
Identyfikowanie problemów z wydajnością bazy danych tempdb
Typowe typy oczekiwania skojarzone z problemami tempdb to PAGELATCH_* (nie PAGEIOLATCH_*). Jednak oczekiwania nie zawsze oznaczają, PAGELATCH_* że masz tempdb rywalizację. To oczekiwanie może też oznaczać, że występuje rywalizacja o stronę danych obiektu użytkownika spowodowana współbieżnymi żądaniami kierowanymi do tej samej strony danych. Aby jeszcze bardziej potwierdzić tempdb rywalizację, użyj sys.dm_exec_requests , aby potwierdzić, że wait_resource wartość zaczyna się od 2:x:y miejsca, gdzie 2 jest tempdb identyfikatorem bazy danych, x jest identyfikatorem pliku i y jest identyfikatorem strony.
W przypadku konfliktów związanych z tempdb typową metodą jest ograniczenie lub przepisanie kodu aplikacji, który opiera się na tempdb. Typowe tempdb obszary użycia obejmują:
- Tabele tymczasowe
- Zmienne tabelaryczne
- Parametry z wartościami przechowywanymi w tabeli
- Zapytania, których plany wykonania wykorzystują sortowanie, złączenia haszujące i spooli
Aby uzyskać więcej informacji, zobacz tempdb in Azure SQL (Baza danych tempdb w usłudze Azure SQL).
Wszystkie bazy danych w elastycznej puli współdzielą tę samą tempdb bazę danych. Wysokie tempdb wykorzystanie miejsca przez jedną bazę danych może mieć wpływ na inne bazy danych w tej samej elastycznej puli.
Najważniejsze zapytania korzystające ze zmiennych tabeli i tabel tymczasowych
Użyj następującego zapytania, aby zidentyfikować najważniejsze zapytania korzystające ze zmiennych tabeli i tabel tymczasowych:
SELECT plan_handle, execution_count, query_plan
INTO #tmpPlan
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_query_plan(plan_handle);
GO
WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS sp)
SELECT plan_handle, stmt.stmt_details.value('@Database', 'varchar(max)') AS 'Database'
, stmt.stmt_details.value('@Schema', 'varchar(max)') AS 'Schema'
, stmt.stmt_details.value('@Table', 'varchar(max)') AS 'table'
INTO #tmp2
FROM
(SELECT CAST(query_plan AS XML) sqlplan, plan_handle FROM #tmpPlan) AS p
CROSS APPLY sqlplan.nodes('//sp:Object') AS stmt(stmt_details);
GO
SELECT t.plan_handle, [Database], [Schema], [table], execution_count
FROM
(SELECT DISTINCT plan_handle, [Database], [Schema], [table]
FROM #tmp2
WHERE [table] LIKE '%@%' OR [table] LIKE '%#%') AS t
INNER JOIN #tmpPlan AS t2 ON t.plan_handle=t2.plan_handle;
GO
DROP TABLE #tmpPlan
DROP TABLE #tmp2
Identyfikowanie długotrwałych transakcji
Użyj następującego zapytania, aby zidentyfikować długotrwałe transakcje. Długotrwałe transakcje uniemożliwiają czyszczenie trwałego magazynu wersji (PVS). Aby uzyskać więcej informacji, zobacz Rozwiązywanie problemów z przyspieszonym odzyskiwaniem bazy danych.
SELECT DB_NAME(dtr.database_id) AS 'database_name',
sess.session_id,
atr.name AS 'tran_name',
atr.transaction_id,
transaction_type,
transaction_begin_time,
database_transaction_begin_time,
transaction_state,
is_user_transaction,
sess.open_transaction_count,
TRIM(REPLACE(
REPLACE(
SUBSTRING(
SUBSTRING(
txt.text,
(req.statement_start_offset / 2) + 1,
((CASE req.statement_end_offset
WHEN -1 THEN
DATALENGTH(txt.text)
ELSE
req.statement_end_offset
END - req.statement_start_offset
) / 2
) + 1
),
1,
1000
),
CHAR(10),
' '
),
CHAR(13),
' '
)
) Running_stmt_text,
recenttxt.text 'MostRecentSQLText'
FROM sys.dm_tran_active_transactions AS atr
INNER JOIN sys.dm_tran_database_transactions AS dtr
ON dtr.transaction_id = atr.transaction_id
LEFT OUTER JOIN sys.dm_tran_session_transactions AS sess
ON sess.transaction_id = atr.transaction_id
LEFT OUTER JOIN sys.dm_exec_requests AS req
ON req.session_id = sess.session_id
AND req.transaction_id = sess.transaction_id
LEFT OUTER JOIN sys.dm_exec_connections AS conn
ON sess.session_id = conn.session_id
OUTER APPLY sys.dm_exec_sql_text(req.sql_handle) AS txt
OUTER APPLY sys.dm_exec_sql_text(conn.most_recent_sql_handle) AS recenttxt
WHERE atr.transaction_type != 2
AND sess.session_id != @@spid
ORDER BY start_time ASC;
Identyfikuj problemy z wydajnością związane z oczekiwaniem na przydział pamięci
Jeśli głównym typem oczekiwania jest RESOURCE_SEMAPHORE, może wystąpić problem z oczekiwaniem na przydział pamięci, w którym zapytania nie mogą rozpocząć wykonywania, dopóki nie uzyskają wystarczająco dużego przydziału pamięci.
Ustal, czy oczekiwanie RESOURCE_SEMAPHORE należy do najczęstszych typów oczekiwań
Użyj następującego zapytania, aby określić, czy oczekiwanie RESOURCE_SEMAPHORE jest głównym typem oczekiwania. Również wzrost pozycji RESOURCE_SEMAPHORE czasu oczekiwania w ostatnim czasie byłby oznaką. Aby uzyskać więcej informacji na temat rozwiązywania problemów z oczekiwaniem na udzielanie pamięci, zobacz Rozwiązywanie problemów z niską wydajnością lub małą ilością pamięci spowodowanych przez przydziały pamięci w programie SQL Server.
SELECT wait_type,
SUM(wait_time) AS total_wait_time_ms
FROM sys.dm_exec_requests AS req
INNER JOIN sys.dm_exec_sessions AS sess
ON req.session_id = sess.session_id
WHERE is_user_process = 1
GROUP BY wait_type
ORDER BY SUM(wait_time) DESC;
Identyfikowanie instrukcji zużywających dużą ilość pamięci
Jeśli wystąpią błędy braku pamięci w usłudze Azure SQL Database, zapoznaj się z sys.dm_os_out_of_memory_events. Aby uzyskać więcej informacji, zobacz Rozwiązywanie problemów z błędami braku pamięci w usłudze Azure SQL Database i bazie danych SQL Fabric.
Najpierw zmodyfikuj poniższy skrypt, aby zaktualizować odpowiednie wartości dla start_time i end_time. Następnie uruchom następujące zapytanie, aby zidentyfikować instrukcje zużywające dużą ilość pamięci:
SELECT IDENTITY (INT, 1, 1) AS rowId,
CAST (query_plan AS XML) AS query_plan,
p.query_id
INTO #tmp
FROM sys.query_store_plan AS p
INNER JOIN sys.query_store_runtime_stats AS r
ON p.plan_id = r.plan_id
INNER JOIN sys.query_store_runtime_stats_interval AS i
ON r.runtime_stats_interval_id = i.runtime_stats_interval_id
WHERE start_time > '2018-10-11 14:00:00.0000000'
AND end_time < '2018-10-17 20:00:00.0000000';
WITH cte
AS (SELECT query_id,
query_plan,
m.c.value('@SerialDesiredMemory', 'INT') AS SerialDesiredMemory
FROM #tmp AS t
CROSS APPLY t.query_plan.nodes('//*:MemoryGrantInfo[@SerialDesiredMemory[. > 0]]') AS m(c))
SELECT TOP 50 cte.query_id,
t.query_sql_text,
cte.query_plan,
CAST (SerialDesiredMemory / 1024. AS DECIMAL (10, 2)) AS SerialDesiredMemory_MB
FROM cte
INNER JOIN sys.query_store_query AS q
ON cte.query_id = q.query_id
INNER JOIN sys.query_store_query_text AS t
ON q.query_text_id = t.query_text_id
ORDER BY SerialDesiredMemory DESC;
Identyfikowanie 10 aktywnych przydziałów pamięci
Użyj następującego zapytania, aby zidentyfikować 10 aktywnych przydziałów pamięci:
SELECT TOP 10 CONVERT(VARCHAR(30), GETDATE(), 121) AS runtime,
r.session_id,
r.blocking_session_id,
r.cpu_time,
r.total_elapsed_time,
r.reads,
r.writes,
r.logical_reads,
r.row_count,
wait_time,
wait_type,
r.command,
OBJECT_NAME(txt.objectid, txt.dbid) 'Object_Name',
TRIM(REPLACE(REPLACE(SUBSTRING(SUBSTRING(TEXT, (r.statement_start_offset / 2) + 1,
( (
CASE r.statement_end_offset
WHEN - 1
THEN DATALENGTH(TEXT)
ELSE r.statement_end_offset
END - r.statement_start_offset
) / 2
) + 1), 1, 1000), CHAR(10), ' '), CHAR(13), ' ')) AS stmt_text,
mg.dop, --Degree of parallelism
mg.request_time, --Date and time when this query requested the memory grant.
mg.grant_time, --NULL means memory has not been granted
mg.requested_memory_kb / 1024.0 requested_memory_mb, --Total requested amount of memory in megabytes
mg.granted_memory_kb / 1024.0 AS granted_memory_mb, --Total amount of memory actually granted in megabytes. NULL if not granted
mg.required_memory_kb / 1024.0 AS required_memory_mb, --Minimum memory required to run this query in megabytes.
max_used_memory_kb / 1024.0 AS max_used_memory_mb,
mg.query_cost, --Estimated query cost.
mg.timeout_sec, --Time-out in seconds before this query gives up the memory grant request.
mg.resource_semaphore_id, --Non-unique ID of the resource semaphore on which this query is waiting.
mg.wait_time_ms, --Wait time in milliseconds. NULL if the memory is already granted.
CASE mg.is_next_candidate --Is this process the next candidate for a memory grant
WHEN 1 THEN 'Yes'
WHEN 0 THEN 'No'
ELSE 'Memory has been granted'
END AS 'Next Candidate for Memory Grant',
qp.query_plan
FROM sys.dm_exec_requests AS r
INNER JOIN sys.dm_exec_query_memory_grants AS mg
ON r.session_id = mg.session_id
AND r.request_id = mg.request_id
CROSS APPLY sys.dm_exec_sql_text(mg.sql_handle) AS txt
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) AS qp
ORDER BY mg.granted_memory_kb DESC;
Monitorowanie połączeń
Możesz użyć widoku sys.dm_exec_connections , aby pobrać informacje o połączeniach ustanowionych z określoną bazą danych i szczegóły każdego połączenia. Jeśli baza danych znajduje się w elastycznej puli i masz wystarczające uprawnienia, widok zwraca zestaw połączeń dla wszystkich baz danych w puli elastycznej. Ponadto widok sys.dm_exec_sessions jest przydatny podczas pobierania informacji o wszystkich aktywnych połączeniach użytkowników i zadaniach wewnętrznych.
Wyświetlanie bieżących sesji
Poniższe zapytanie pobiera informacje dotyczące bieżącego połączenia i sesji. Aby wyświetlić wszystkie połączenia i sesje, usuń klauzulę WHERE .
Wszystkie aktualnie wykonywane sesje w bazie danych są widoczne tylko wtedy, gdy masz uprawnienie VIEW DATABASE STATE do bazy danych podczas wykonywania zapytań względem widoków sys.dm_exec_requests i sys.dm_exec_sessions. W przeciwnym razie zobaczysz tylko bieżącą sesję.
SELECT c.session_id,
c.net_transport,
c.encrypt_option,
c.auth_scheme,
s.host_name,
s.program_name,
s.client_interface_name,
s.login_name,
s.nt_domain,
s.nt_user_name,
s.original_login_name,
c.connect_time,
s.login_time
FROM sys.dm_exec_connections AS c
INNER JOIN sys.dm_exec_sessions AS s
ON c.session_id = s.session_id
WHERE c.session_id = @@SPID; --Remove to view all sessions, if permissions allow
Monitorowanie wydajności zapytań
Wolne lub długotrwałe zapytania mogą zużywać znaczne zasoby systemowe. W tej sekcji pokazano, jak używać dynamicznych widoków zarządzania do wykrywania kilku typowych problemów z wydajnością zapytań przy użyciu dynamicznego widoku zarządzania sys.dm_exec_query_stats . Widok zawiera jeden wiersz dla każdej instrukcji zapytania w ramach buforowanego planu, a czas istnienia tych wierszy jest związany z samym planem. Gdy plan zostanie usunięty z pamięci podręcznej, odpowiednie wiersze zostaną wyeliminowane z tego widoku. Jeśli zapytanie nie ma buforowanego planu, na przykład z powodu użycia OPTION (RECOMPILE), nie jest obecne w wynikach tego widoku.
Znajdowanie najważniejszych zapytań według czasu procesora CPU
Poniższy przykład zwraca informacje o 15 pierwszych zapytaniach sklasyfikowanych według średniego czasu procesora CPU na wykonanie. W tym przykładzie zapytania są agregowane zgodnie z ich skrótem zapytania, dzięki czemu zapytania równoważne logicznie są grupowane według skumulowanego użycia zasobów.
SELECT TOP 15 query_stats.query_hash AS Query_Hash,
SUM(query_stats.total_worker_time) / SUM(query_stats.execution_count) AS Avg_CPU_Time,
MIN(query_stats.statement_text) AS Statement_Text
FROM (SELECT QS.*,
SUBSTRING(ST.text, (QS.statement_start_offset / 2) + 1, (
(CASE statement_end_offset
WHEN -1 THEN DATALENGTH(ST.text)
ELSE QS.statement_end_offset END
- QS.statement_start_offset) / 2) + 1) AS statement_text
FROM sys.dm_exec_query_stats AS QS
CROSS APPLY sys.dm_exec_sql_text(QS.sql_handle) AS ST) AS query_stats
GROUP BY query_stats.query_hash
ORDER BY Avg_CPU_Time DESC;
Monitoruj plany zapytań pod kątem łącznego czasu użycia procesora
Nieefektywny plan zapytania może również zwiększyć użycie procesora CPU. Poniższy przykład ustala, które zapytanie zużyło łącznie najwięcej czasu procesora w ostatnim czasie.
SELECT highest_cpu_queries.plan_handle,
highest_cpu_queries.total_worker_time,
q.dbid,
q.objectid,
q.number,
q.encrypted,
q.[text]
FROM (SELECT TOP 15 qs.plan_handle,
qs.total_worker_time
FROM sys.dm_exec_query_stats AS qs
ORDER BY qs.total_worker_time DESC) AS highest_cpu_queries
CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS q
ORDER BY highest_cpu_queries.total_worker_time DESC;
Monitorowanie zablokowanych zapytań
Powolne lub długotrwałe zapytania mogą przyczynić się do nadmiernego użycia zasobów i być konsekwencją zablokowanych zapytań. Przyczyną blokowania może być słaba konstrukcja aplikacji, złe plany zapytań, brak przydatnych indeksów itd.
Możesz użyć widoku sys.dm_tran_locks, aby uzyskać informacje o bieżącej aktywności blokowania w bazie danych. Aby zapoznać się z przykładami kodu, zobacz sys.dm_tran_locks. Aby uzyskać więcej informacji na temat rozwiązywania problemów z blokowaniem, zobacz Omówienie i rozwiązywanie problemów z blokowaniem.
Monitoruj zakleszczenia
W niektórych przypadkach co najmniej dwa zapytania mogą blokować się nawzajem, co powoduje zakleszczenie.
Możesz utworzyć ślad Extended Events w celu przechwytywania zdarzeń zakleszczeń, a następnie znaleźć powiązane zapytania i ich plany wykonywania w Query Store. Więcej informacji znajdziesz w Analizowanie i zapobieganie zakleszczeniom w usłudze Azure SQL Database i SQL Database w Microsoft Fabric. Dowiedz się więcej o zakleszczeniach w przewodniku "Zakleszczenia".
Uprawnienia
W Azure SQL Database, w zależności od rozmiaru obliczeniowego, opcji wdrożenia i danych w DMV, wykonywanie zapytań dotyczących dynamicznego widoku monitorowania może wymagać VIEW DATABASE STATE lub VIEW SERVER PERFORMANCE STATE, albo VIEW SERVER SECURITY STATE uprawnień. Ostatnie dwa uprawnienia są uwzględnione w uprawnieniach VIEW SERVER STATE . Uprawnienia do wyświetlania stanu serwera są przyznawane za pośrednictwem członkostwa w odpowiednich rolach serwera. Aby określić, które uprawnienia są wymagane do wykonywania zapytań dotyczących określonego dynamicznego widoku zarządzania, zobacz Dynamiczne widoki zarządzania systemu i znajdź artykuł opisujący dynamiczny widok zarządzania.
Aby przyznać użytkownikowi bazy danych uprawnienie VIEW DATABASE STATE, uruchom następujące zapytanie, zastępując database_user nazwą podmiotu zabezpieczeń użytkownika w bazie danych:
GRANT VIEW DATABASE STATE TO [database_user];
Aby nadać członkostwo w roli serwera ##MS_ServerStateReader## nazwie logowania login_name na serwerze logicznym, połącz się z bazą danych master, a następnie uruchom przykładowe zapytanie:
ALTER SERVER ROLE [##MS_ServerStateReader##] ADD MEMBER [login_name];
Może minąć kilka minut, zanim przyznanie uprawnień zacznie obowiązywać. Aby uzyskać więcej informacji, zobacz Ograniczenia ról na poziomie serwera.
Powiązana zawartość
- Diagnozowanie i rozwiązywanie problemów z wysokim użyciem procesora CPU w usłudze Azure SQL Database i bazie danych SQL Database w usłudze Microsoft Fabric
- Dostrajanie aplikacji i baz danych pod kątem wydajności w usłudze Azure SQL Database
- Omówienie i rozwiązywanie problemów z blokowaniem
- Analizowanie i zapobieganie zakleszczeniom w Azure SQL Database oraz bazie danych SQL w Fabric
- Szczegółowe informacje o wydajności zapytań dla usługi Azure SQL Database
- sys.dm_db_resource_stats
- sys.resource_stats
- sys.dm_elastic_pool_resource_stats
- sys.elastic_pool_resource_stats