Monitorování výkonu spravované instance Microsoft Azure SQL pomocí zobrazení dynamické správy

Platí pro:Azure SQL Managed Instance

Spravovaná instance Microsoft Azure SQL umožňuje podmnožinu zobrazení dynamické správy (DMV) diagnostikovat problémy s výkonem, které můžou být způsobené blokovanými nebo dlouhotrvajícími dotazy, kritickými body prostředků, špatnými plány dotazů atd. Tento článek obsahuje informace o tom, jak zjišťovat běžné problémy s výkonem pomocí zobrazení dynamické správy.

Tento článek se týká služby Azure SQL Managed Instance, viz také monitorování výkonu služby Microsoft Azure SQL Database pomocí zobrazení dynamické správy.

Oprávnění

V Azure SQL Managed Instance vyžaduje dotazování zobrazení dynamické správy oprávnění ZOBRAZIT STAV SERVERU.

GRANT VIEW SERVER STATE TO database_user;

V instanci SQL Serveru a ve službě Azure SQL Managed Instance vrátí zobrazení dynamické správy informace o stavu serveru.

Identifikace problémů s výkonem procesoru

Pokud je spotřeba procesoru delší dobu vyšší než 80 %, zvažte následující kroky pro řešení potíží:

K problému s procesorem dochází teď

Pokud k problému dochází právě teď, existují dva možné scénáře:

Mnoho jednotlivých dotazů, které kumulativní spotřebovávají vysoké využití procesoru

K identifikaci hodnot hash nejvyšších dotazů použijte následující dotaz:

PRINT '-- top 10 Active CPU Consuming Queries (aggregated)--';
SELECT TOP 10 GETDATE() runtime, *
FROM (SELECT query_stats.query_hash, SUM(query_stats.cpu_time) 'Total_Request_Cpu_Time_Ms', SUM(logical_reads) 'Total_Request_Logical_Reads', MIN(start_time) 'Earliest_Request_start_Time', COUNT(*) '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;

Dlouho trvající dotazy využívající procesor jsou stále spuštěné

Pomocí následujícího dotazu identifikujte tyto dotazy:

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

K problému s procesorem došlo v minulosti.

Pokud k problému došlo v minulosti a chcete provést analýzu původní příčiny, použijte úložiště dotazů. Uživatelé s přístupem k databázi můžou dotazovat data úložiště dotazů pomocí T-SQL. Výchozí konfigurace úložiště dotazů používají členitost 1 hodinu. Pomocí následujícího dotazu se podívejte na aktivitu pro dotazy s vysokým využitím procesoru. Tento dotaz vrátí prvních 15 dotazů využívajících procesor. Nezapomeňte změnit rsi.start_time >= DATEADD(hour, -2, GETUTCDATE():

-- Top 15 CPU consuming queries by query hash
-- note that a query  hash can have many query id if not parameterized or not parameterized properly
-- it grabs a sample query text by min
WITH AggregatedCPU AS (SELECT q.query_hash, SUM(count_executions * avg_cpu_time / 1000.0) AS total_cpu_millisec, SUM(count_executions * avg_cpu_time / 1000.0)/ SUM(count_executions) AS avg_cpu_millisec, MAX(rs.max_cpu_time / 1000.00) AS max_cpu_millisec, 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
                            JOIN sys.query_store_query AS q ON qt.query_text_id=q.query_text_id
                            JOIN sys.query_store_plan AS p ON q.query_id=p.query_id
                            JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id=p.plan_id
                            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_millisec, avg_cpu_millisec, max_cpu_millisec, 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_millisec DESC, query_hash ASC) AS RN
                                                              FROM AggregatedCPU)
SELECT OD.query_hash, OD.total_cpu_millisec, OD.avg_cpu_millisec, OD.max_cpu_millisec, 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.RN
FROM OrderedCPU AS OD
WHERE OD.RN<=15
ORDER BY total_cpu_millisec DESC;

Jakmile identifikujete problematické dotazy, je čas tyto dotazy ladit, aby se snížilo využití procesoru. Pokud nemáte čas ladit dotazy, můžete se také rozhodnout upgradovat SLO spravované instance, abyste tento problém vyřešili.

Identifikace problémů s výkonem vstupně-výstupních operací

Při identifikaci problémů s výkonem vstupně-výstupních operací jsou nejčastějšími typy čekání následující:

  • PAGEIOLATCH_*

    V případě problémů se vstupně-výstupními operacemi datových souborů (včetně PAGEIOLATCH_SH, PAGEIOLATCH_EX) PAGEIOLATCH_UP Pokud název typu čekání obsahuje vstupně-výstupní operace, odkazuje na problém se vstupně-výstupními operacemi. Pokud název západky stránky neobsahuje vstupně-výstupní operace, odkazuje na jiný typ problému (například tempdb kolize).

  • WRITE_LOG

    Problémy se vstupně-výstupními operacemi transakčního protokolu

Pokud právě teď dochází k problému se vstupně-výstupními operacemi

Pomocí sys.dm_exec_requests nebo sys.dm_os_waiting_taskswait_typewait_time

Pro možnost 2 můžete použít následující dotaz na úložiště dotazů pro vstupně-výstupní operace související s vyrovnávací pamětí k zobrazení posledních dvou hodin sledované aktivity:

-- 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
                         JOIN sys.query_store_query AS q ON qt.query_text_id=q.query_text_id
                         JOIN sys.query_store_plan AS p ON q.query_id=p.query_id
                         JOIN sys.query_store_wait_stats AS waits ON waits.plan_id=p.plan_id
                         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 RN
                                                        FROM Aggregated)
SELECT OD.query_hash, OD.total_executions, OD.total_wait_time_ms, OD.sampled_query_text, OD.wait_category_desc, OD.RN
FROM Ordered AS OD
WHERE OD.RN<=15
ORDER BY total_wait_time_ms DESC;
GO

Zobrazení celkového počtu vstupně-výstupních operací protokolu pro čekání WRITELOG

Pokud je WRITELOGtyp čekání, pomocí následujícího dotazu zobrazte celkový počet vstupně-výstupních operací protokolu podle příkazu:

-- 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_millisec,
           SUM(count_executions * avg_cpu_time / 1000.0) / SUM(count_executions) AS avg_cpu_millisec,
           SUM(count_executions * avg_log_bytes_used) AS total_log_bytes_used,
           MAX(rs.max_cpu_time / 1000.00) AS max_cpu_millisec,
           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
        JOIN sys.query_store_query AS q
            ON qt.query_text_id = q.query_text_id
        JOIN sys.query_store_plan AS p
            ON q.query_id = p.query_id
        JOIN sys.query_store_runtime_stats AS rs
            ON rs.plan_id = p.plan_id
        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 RN
    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.RN
FROM OrderedLogUsed AS OD
WHERE OD.RN <= 15
ORDER BY total_log_bytes_used DESC;
GO

Identifikace tempdb problémů s výkonem

Při identifikaci problémů s výkonem vstupně-výstupních operací jsou PAGELATCH_* hlavní typy čekání spojené s tempdb problémy (nePAGEIOLATCH_*). PAGELATCH_* Čekání ale neznamená, že máte tempdb kolize. Toto čekání může také znamenat, že kvůli souběžným požadavkům, které cílí na stejnou stránku dat, dochází na stránce dat ke kolizím uživatelských objektů. Pokud chcete dále potvrdit tempdb kolize, použijte sys.dm_exec_requests k potvrzení, že hodnota wait_resource začíná místem 2:x:y , kde 2 je tempdb ID databáze, x je ID souboru a y je ID stránky.

Pro tempdb kolizí je běžnou metodou omezení nebo přepsání kódu aplikace, který spoléhá na tempdb. Mezi běžné tempdb oblasti použití patří:

  • Dočasné tabulky
  • Proměnné tabulek
  • Parametry vracející tabulku
  • Využití úložiště verzí (přidružené k dlouhotrvajícím transakcím)
  • Dotazy s plány dotazů, které využívají řazení, hash spojení a zařazování

Nejčastější dotazy, které používají proměnné tabulek a dočasné tabulky

Pomocí následujícího dotazu identifikujte nejčastější dotazy, které používají proměnné tabulky a dočasné tabulky:

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)') 'Database', stmt.stmt_details.value('@Schema', 'varchar(max)') 'Schema', stmt.stmt_details.value('@Table', 'varchar(max)') '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
    JOIN #tmpPlan AS t2 ON t.plan_handle=t2.plan_handle;

Identifikace dlouhotrvajících transakcí

Pomocí následujícího dotazu identifikujte dlouhotrvající transakce. Dlouhotrvající transakce brání vyčištění úložiště verzí.

SELECT DB_NAME(dtr.database_id) '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 JOIN sys.dm_tran_session_transactions AS sess
        ON sess.transaction_id = atr.transaction_id
    LEFT JOIN sys.dm_exec_requests AS req
        ON req.session_id = sess.session_id
           AND req.transaction_id = sess.transaction_id
    LEFT 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;

Identifikace problémů s výkonem čekání na přidělení paměti

Pokud je RESOURCE_SEMAHPORE váš hlavní typ čekání a nemáte problém s vysokým využitím procesoru, může dojít k problému s čekáním na přidělení paměti.

Určení, jestli RESOURCE_SEMAHPORE je čekání hlavní čekání

Pomocí následujícího dotazu určete, jestli RESOURCE_SEMAHPORE je čekání hlavní čekání.

SELECT wait_type,
       SUM(wait_time) AS total_wait_time_ms
FROM sys.dm_exec_requests AS req
    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;

Identifikace příkazů s vysokým využitím paměti

Pokud dojde k chybám s nedostatkem paměti, zkontrolujte sys.dm_os_out_of_memory_events.

Pomocí následujícího dotazu identifikujte příkazy s vysokým využitím paměti:

SELECT IDENTITY(INT, 1, 1) rowId,
    CAST(query_plan AS XML) query_plan,
    p.query_id
INTO #tmp
FROM sys.query_store_plan AS p
    JOIN sys.query_store_runtime_stats AS r
        ON p.plan_id = r.plan_id
    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';
GO
;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)) SerialDesiredMemory_MB
FROM cte
    JOIN sys.query_store_query AS q
        ON cte.query_id = q.query_id
    JOIN sys.query_store_query_text AS t
        ON q.query_text_id = t.query_text_id
ORDER BY SerialDesiredMemory DESC;

Identifikace přidělení paměti

Pomocí následujícího dotazu identifikujte 10 nejlepších grantů aktivní paměti:

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),
                ' '
            )
            ) 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
    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;

Výpočet velikosti databáze a objektů

Následující dotaz vrátí velikost databáze (v megabajtech):

-- Calculates the size of the database.
SELECT SUM(CAST(FILEPROPERTY(name, 'SpaceUsed') AS bigint) * 8192.) / 1024 / 1024 AS DatabaseSizeInMB
FROM sys.database_files
WHERE type_desc = 'ROWS';
GO

Následující dotaz vrátí velikost jednotlivých objektů (v megabajtech) v databázi:

-- Calculates the size of individual database objects.
SELECT sys.objects.name, SUM(reserved_page_count) * 8.0 / 1024
FROM sys.dm_db_partition_stats, sys.objects
WHERE sys.dm_db_partition_stats.object_id = sys.objects.object_id
GROUP BY sys.objects.name;
GO

Monitorování připojení

Pomocí zobrazení sys.dm_exec_connections můžete načíst informace o připojeních vytvořených ke konkrétní spravované instanci a podrobnostem jednotlivých připojení. Kromě toho je zobrazení sys.dm_exec_sessions užitečné při načítání informací o všech aktivních připojeních uživatelů a interních úlohách.

Následující dotaz načte informace o aktuálním připojení:

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
JOIN sys.dm_exec_sessions AS s
    ON c.session_id = s.session_id
WHERE c.session_id = @@SPID;

Monitorování využití prostředků

Využití prostředků můžete monitorovat pomocí úložiště dotazů stejně jako na SQL Serveru.

Využití můžete monitorovat také pomocí sys.dm_db_resource_stats a sys.server_resource_stats.

sys.dm_db_resource_stats

V každé databázi můžete použít zobrazení sys.dm_db_resource_stats . Zobrazení sys.dm_db_resource_stats zobrazuje data o použití nedávného prostředku vzhledem k úrovni služby. Průměrné procento procesoru, vstupně-výstupních operací dat, zápisů protokolů a paměti se zaznamenávají každých 15 sekund a uchovávají se po dobu 1 hodiny.

Vzhledem k tomu, že toto zobrazení poskytuje podrobnější přehled o použití prostředků, použijte sys.dm_db_resource_stats nejprve k analýze aktuálního stavu nebo řešení potíží. Tento dotaz například ukazuje průměrné a maximální využití prostředků pro aktuální databázi za poslední hodinu:

SELECT  
    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'
FROM sys.dm_db_resource_stats;  

Další dotazy najdete v příkladech v sys.dm_db_resource_stats.

sys.server_resource_stats

Pomocí sys.server_resource_stats můžete vrátit data o využití procesoru, vstupně-výstupních operacích a úložišti pro spravovanou instanci Azure SQL. Data se shromažďují a agregují v pětiminutových intervalech. Každé 15sekundové hlášení má jeden řádek. Vrácená data zahrnují využití procesoru, velikost úložiště, využití vstupně-výstupních operací a skladovou položku spravované instance. Historická data se uchovávají přibližně 14 dnů.

Příklady ukazují různé způsoby, jak můžete pomocí sys.server_resource_stats zobrazení katalogu získat informace o tom, jak vaše instance používá prostředky.

  1. Následující příklad vrátí průměrné využití procesoru za posledních 7 dnů:

    DECLARE @s datetime;  
    DECLARE @e datetime;  
    SET @s= DateAdd(d,-7,GetUTCDate());  
    SET @e= GETUTCDATE();  
    SELECT AVG(avg_cpu_percent) AS Average_Compute_Utilization   
    FROM sys.server_resource_stats   
    WHERE start_time BETWEEN @s AND @e;
    GO
    
  2. Následující příklad vrátí průměrný prostor úložiště používaný vaší instancí za den, který umožňuje analýzu trendu růstu:

    DECLARE @s datetime;  
    DECLARE @e datetime;  
    SET @s= DateAdd(d,-7,GetUTCDate());  
    SET @e= GETUTCDATE();  
    SELECT Day = convert(date, start_time), AVG(storage_space_used_mb) AS Average_Space_Used_mb
    FROM sys.server_resource_stats   
    WHERE start_time BETWEEN @s AND @e
    GROUP BY convert(date, start_time)
    ORDER BY convert(date, start_time);
    GO
    

Maximální počet souběžných požadavků

Pokud chcete zobrazit aktuální počet souběžných požadavků, spusťte tento dotaz Transact-SQL ve vaší databázi:

SELECT COUNT(*) AS [Concurrent_Requests]
FROM sys.dm_exec_requests R;

Pokud chcete analyzovat úlohu jednotlivých databází, upravte tento dotaz tak, aby filtruje konkrétní databázi, kterou chcete analyzovat. Pokud máte například databázi s názvem MyDatabase, vrátí tento dotaz Transact-SQL počet souběžných požadavků v této databázi:

SELECT COUNT(*) AS [Concurrent_Requests]
FROM sys.dm_exec_requests R
INNER JOIN sys.databases D ON D.database_id = R.database_id
AND D.name = 'MyDatabase';

Jedná se jen o snímek v jednom bodu v čase. Pokud chcete lépe porozumět požadavkům na úlohy a souběžné požadavky na požadavky, budete muset v průběhu času shromáždit mnoho vzorků.

Maximální počet souběžných přihlášení

Vzory uživatelů a aplikací můžete analyzovat, abyste získali představu o frekvenci přihlášení. Zatížení reálného světa můžete spustit také v testovacím prostředí, abyste měli jistotu, že nedosahujete tohoto nebo jiného omezení, které probereme v tomto článku. Neexistuje jediný dotaz ani zobrazení dynamické správy, které vám může zobrazit souběžné počty přihlášení nebo historii.

Pokud stejný připojovací řetězec používá více klientů, služba každé přihlášení ověří. Pokud se 10 uživatelů současně připojuje k databázi pomocí stejného uživatelského jména a hesla, bude k dispozici 10 souběžných přihlášení. Tento limit platí jenom pro dobu trvání přihlášení a ověřování. Pokud se stejných 10 uživatelů připojuje k databázi postupně, počet souběžných přihlášení by nikdy nebyl větší než 1.

Maximální počet relací

Pokud chcete zobrazit počet aktuálních aktivních relací, spusťte tento dotaz Transact-SQL ve vaší databázi:

SELECT COUNT(*) AS [Sessions]
FROM sys.dm_exec_connections;

Pokud analyzujete úlohu SQL Serveru, upravte dotaz tak, aby se zaměřoval na konkrétní databázi. Tento dotaz vám pomůže určit možné potřeby relace pro databázi, pokud uvažujete o přesunu do Azure.

SELECT COUNT(*) AS [Sessions]
FROM sys.dm_exec_connections C
INNER JOIN sys.dm_exec_sessions S ON (S.session_id = C.session_id)
INNER JOIN sys.databases D ON (D.database_id = S.database_id)
WHERE D.name = 'MyDatabase';

Tyto dotazy znovu vrátí počet k určitému bodu v čase. Pokud v průběhu času shromáždíte více vzorků, budete mít nejlepší představu o využití relace.

Monitorování výkonu dotazů

Pomalé nebo dlouhotrvající dotazy můžou spotřebovávat významné systémové prostředky. Tato část ukazuje, jak pomocí zobrazení dynamické správy detekovat několik běžných problémů s výkonem dotazů.

Hledání nejčastějších dotazů N

Následující příklad vrátí informace o prvních pěti dotazech seřazených podle průměrného času procesoru. Tento příklad agreguje dotazy podle jejich hodnoty hash dotazu, aby se logicky ekvivalentní dotazy seskupily podle kumulativní spotřeby prostředků.

SELECT TOP 5 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 2 DESC;

Monitorování blokovaných dotazů

Pomalé nebo dlouhotrvající dotazy můžou přispívat k nadměrné spotřebě prostředků a být důsledkem blokovaných dotazů. Příčinou blokování může být špatný návrh aplikace, chybné plány dotazů, nedostatek užitečných indexů atd. Pomocí zobrazení sys.dm_tran_locks můžete získat informace o aktuální aktivitě uzamčení v databázi. Příklad kódu najdete v sys.dm_tran_locks. Další informace o řešení potíží s blokováním najdete v tématu Vysvětlení a řešení problémů blokujících Azure SQL.

Monitorování zablokování

V některých případech můžou dva nebo více dotazů vzájemně blokovat, což vede k vzájemnému zablokování.

Můžete vytvořit trasování rozšířených událostí databáze pro zachycení událostí vzájemného zablokování a pak vyhledat související dotazy a jejich plány provádění v úložišti dotazů.

V případě služby Azure SQL Managed Instance si projděte nástroje vzájemného zablokování v průvodci vzájemným zablokováním.

Monitorování plánů dotazů

Neefektivní plán dotazů může také zvýšit spotřebu procesoru. Následující příklad používá zobrazení sys.dm_exec_query_stats k určení, který dotaz používá nejvíce kumulativní procesoru.

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 50
        qs.plan_handle,
        qs.total_worker_time
    FROM
        sys.dm_exec_query_stats 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;

Další možnosti monitorování

Monitorování s využitím SQL Přehledy (Preview)

Azure Monitor SQL Přehledy (Preview) je nástroj pro monitorování instancí služby Azure SQL Managed Instance, databází ve službě Azure SQL Database a SQL Serveru na virtuálních počítačích Azure SQL. K záznamu dat ze zobrazení dynamické správy (DMV) používá služba vzdáleného agenta a přesměrovává data do služby Azure Log Analytics, kde je můžete monitorovat a analyzovat. Tato data můžete zobrazit ze služby Azure Monitor v zadaných zobrazeních nebo přistupovat k datům protokolu přímo, abyste mohli spouštět dotazy a analyzovat trendy. Pokud chcete začít používat azure Monitor SQL Přehledy (Preview), přečtěte si téma Povolení SQL Přehledy (Preview).

Monitorování pomocí služby Azure Monitor

Azure Monitor poskytuje celou řadu skupin shromažďování diagnostických dat, metrik a koncových bodů pro monitorování služby Azure SQL Managed Instance. Další informace najdete v tématu Monitorování služby Azure SQL Managed Instance pomocí služby Azure Monitor. Azure SQL Analytics (Preview) je integrace se službou Azure Monitor, kde mnoho řešení monitorování už není aktivní ve vývoji. Další možnosti monitorování najdete v tématu Monitorování a ladění výkonu ve službě Azure SQL Managed Instance a Azure SQL Database.

Viz také

Další kroky