Prestaties van Microsoft Azure SQL Managed Instance bewaken met dynamische beheerweergaven

Van toepassing op: Azure SQL Managed Instance

Met Microsoft Azure SQL Managed Instance kan een subset van dynamische beheerweergaven (DMV's) prestatieproblemen vaststellen, die kunnen worden veroorzaakt door geblokkeerde of langlopende query's, resourceknelpunten, slechte queryplannen, enzovoort. Dit artikel bevat informatie over het detecteren van veelvoorkomende prestatieproblemen met behulp van dynamische beheerweergaven.

Dit artikel gaat over Azure SQL Managed Instance. Zie ook De prestaties van Microsoft Azure SQL Database bewaken met behulp van dynamische beheerweergaven.

Bevoegdheden

Voor het uitvoeren van een query op een dynamisch beheerweergave in Azure SQL Managed Instance zijn MACHTIGINGEN VOOR VIEW SERVER STATE vereist.

GRANT VIEW SERVER STATE TO database_user;

In een exemplaar van SQL Server en in Azure SQL Managed Instance retourneren dynamische beheerweergaven serverstatusgegevens.

CPU-prestatieproblemen identificeren

Als het CPU-verbruik gedurende langere perioden hoger is dan 80%, kunt u de volgende stappen voor probleemoplossing overwegen:

Het CPU-probleem treedt nu op

Als het probleem zich op dit moment voordoet, zijn er twee mogelijke scenario's:

Veel afzonderlijke query's die cumulatief hoge CPU verbruiken

Gebruik de volgende query om topquery-hashes te identificeren:

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;

Langlopende query's die CPU verbruiken, worden nog steeds uitgevoerd

Gebruik de volgende query om deze query's te identificeren:

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

Het CPU-probleem is in het verleden opgetreden

Als het probleem zich in het verleden heeft voorgedaan en u een hoofdoorzaakanalyse wilt uitvoeren, gebruikt u Query Store. Gebruikers met databasetoegang kunnen T-SQL gebruiken om query's uit te voeren op Query Store-gegevens. Standaardconfiguraties van Query Store gebruiken een granulariteit van 1 uur. Gebruik de volgende query om te kijken naar activiteit voor query's met een hoog CPU-verbruik. Deze query retourneert de top 15 CPU-verbruikende query's. Vergeet niet om het volgende te wijzigen 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;

Zodra u de problematische query's hebt geïdentificeerd, is het tijd om deze query's af te stemmen om het CPU-gebruik te verminderen. Als u geen tijd hebt om de query's af te stemmen, kunt u er ook voor kiezen om de SLO van het beheerde exemplaar bij te werken om het probleem te omzeilen.

IO-prestatieproblemen identificeren

Bij het identificeren van IO-prestatieproblemen zijn de belangrijkste wachttypen die verband houden met IO-problemen:

  • PAGEIOLATCH_*

    Voor IO-problemen met gegevensbestanden (inclusief PAGEIOLATCH_SH, PAGEIOLATCH_EX, PAGEIOLATCH_UP). Als de naam van het wachttype IO bevat, verwijst deze naar een IO-probleem. Als er geen IO in de wachtnaam van de paginavergrendeling staat, verwijst deze naar een ander type probleem (bijvoorbeeld tempdb conflicten).

  • WRITE_LOG

    Voor io-problemen met transactielogboeken.

Als het IO-probleem zich op dit moment voordoet

Gebruik de sys.dm_exec_requests of sys.dm_os_waiting_tasks om de wait_type en wait_timete zien.

Voor optie 2 kunt u de volgende query voor Query Store gebruiken voor buffergerelateerde IO om de laatste twee uur bijgehouden activiteit weer te geven:

-- 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

Totale logboek-IO voor WRITELOG-wachttijden weergeven

Als het wachttype is WRITELOG, gebruikt u de volgende query om het totale io-logboek per instructie weer te geven:

-- 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

Prestatieproblemen identificeren tempdb

Bij het identificeren van I/O-prestatieproblemen zijn de belangrijkste wachttypen die zijn gekoppeld aan tempdb problemen PAGELATCH_* (niet PAGEIOLATCH_*). PAGELATCH_* Wachttijden betekenen echter niet altijd dat u conflicten hebttempdb. Dit wachten kan ook betekenen dat er een conflict voor een gegevenspagina voor gebruikersobjecten is opgetreden vanwege gelijktijdige aanvragen voor dezelfde gegevenspagina. Als u conflicten verder wilt bevestigen tempdb , gebruikt u sys.dm_exec_requests om te bevestigen dat de wait_resource waarde begint met 2:x:y waar 2 de database-id is tempdb , x de bestands-id is en y de pagina-id is.

Voor tempdb conflicten is een algemene methode het verminderen of herschrijven van toepassingscode tempdbdie afhankelijk is van . Algemene tempdb gebruiksgebieden zijn onder andere:

  • Tijdelijke tabellen
  • Tabelvariabelen
  • Tabelwaardeparameters
  • Gebruik van versieopslag (gekoppeld aan langlopende transacties)
  • Query's met queryplannen die gebruikmaken van sorteringen, hash joins en spools

Topquery's die gebruikmaken van tabelvariabelen en tijdelijke tabellen

Gebruik de volgende query om de belangrijkste query's te identificeren die gebruikmaken van tabelvariabelen en tijdelijke tabellen:

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;

Langlopende transacties identificeren

Gebruik de volgende query om langlopende transacties te identificeren. Langlopende transacties verhinderen het opschonen van versieopslag.

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;

Problemen met wachttijden voor geheugentoekenning identificeren

Als uw belangrijkste wachttype is RESOURCE_SEMAHPORE en u geen probleem hebt met hoog CPU-gebruik, is er mogelijk een probleem met de geheugentoekenning.

Bepalen of een RESOURCE_SEMAHPORE wachttijd een topwacht is

Gebruik de volgende query om te bepalen of een RESOURCE_SEMAHPORE wachttijd een topwacht is

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;

Instructies voor hoog geheugengebruik identificeren

Als er onvoldoende geheugenfouten optreden, dan raadpleegt u sys.dm_os_out_of_memory_events.

Gebruik de volgende query om instructies te identificeren die veel geheugen verbruiken:

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;

De geheugentoelagen identificeren

Gebruik de volgende query om de tien belangrijkste actieve geheugentoelagen te identificeren:

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;

De grootte van de database en objecten berekenen

Met de volgende query wordt de grootte van uw database geretourneerd (in megabytes):

-- 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

Met de volgende query wordt de grootte van afzonderlijke objecten geretourneerd (in megabytes):

-- 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

Verbindingen bewaken

U kunt de weergave sys.dm_exec_connections gebruiken om informatie op te halen over de verbindingen die tot stand zijn gebracht met een specifiek beheerd exemplaar en de details van elke verbinding. Daarnaast is de weergave sys.dm_exec_sessions handig bij het ophalen van informatie over alle actieve gebruikersverbindingen en interne taken.

Met de volgende query wordt informatie opgehaald over de huidige verbinding:

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;

Resourcegebruik bewaken

U kunt het resourcegebruik bewaken met behulp van de Query Store, net zoals in SQL Server.

U kunt ook het gebruik bewaken met behulp van sys.dm_db_resource_stats en sys.server_resource_stats.

sys.dm_db_resource_stats

U kunt de sys.dm_db_resource_stats weergave in elke database gebruiken. In sys.dm_db_resource_stats de weergave ziet u recente gegevens over resourcegebruik ten opzichte van de servicelaag. Gemiddelde percentages voor CPU, gegevens-I/O, schrijfbewerkingen in logboeken en geheugen worden elke 15 seconden vastgelegd en gedurende 1 uur onderhouden.

Omdat deze weergave een gedetailleerder overzicht biedt van het gebruik van resources, gebruikt sys.dm_db_resource_stats u eerst voor een analyse van de huidige status of probleemoplossing. In deze query ziet u bijvoorbeeld het gemiddelde en maximale resourcegebruik voor de huidige database in het afgelopen uur:

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;  

Zie de voorbeelden in sys.dm_db_resource_stats voor andere query's.

sys.server_resource_stats

U kunt sys.server_resource_stats gebruiken om CPU-gebruik, IO- en opslaggegevens te retourneren voor een beheerd exemplaar van Azure SQL. De gegevens worden verzameld en geaggregeerd binnen vijf minuten intervallen. Er is één rij voor elke 15 seconden rapportage. De geretourneerde gegevens omvatten CPU-gebruik, opslaggrootte, IO-gebruik en beheerde exemplaar-SKU. Historische gegevens worden ongeveer 14 dagen bewaard.

In de voorbeelden ziet u verschillende manieren waarop u de sys.server_resource_stats catalogusweergave kunt gebruiken om informatie te krijgen over hoe uw exemplaar resources gebruikt.

  1. In het volgende voorbeeld wordt het gemiddelde CPU-gebruik in de afgelopen zeven dagen geretourneerd:

    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. In het volgende voorbeeld wordt de gemiddelde opslagruimte geretourneerd die door uw exemplaar per dag wordt gebruikt, om groeitrendingsanalyse mogelijk te maken:

    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
    

Maximum aantal gelijktijdige aanvragen

Als u het huidige aantal gelijktijdige aanvragen wilt zien, voert u deze Transact-SQL-query uit op uw database:

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

Als u de workload van een afzonderlijke database wilt analyseren, wijzigt u deze query om te filteren op de specifieke database die u wilt analyseren. Als u bijvoorbeeld een database met de naam MyDatabasehebt, retourneert deze Transact-SQL-query het aantal gelijktijdige aanvragen in die database:

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

Dit is slechts een momentopname op een bepaald moment. Als u meer inzicht wilt krijgen in uw workload en gelijktijdige aanvraagvereisten, moet u in de loop van de tijd veel voorbeelden verzamelen.

Maximum aantal gelijktijdige aanmeldingen

U kunt uw gebruikers- en toepassingspatronen analyseren om een idee te krijgen van de frequentie van aanmeldingen. U kunt ook echte laadbewerkingen uitvoeren in een testomgeving om ervoor te zorgen dat u niet aan deze of andere limieten komt die in dit artikel worden besproken. Er is geen enkele query of dynamische beheerweergave (DMV) waarmee u gelijktijdige aanmeldingsaantallen of geschiedenis kunt weergeven.

Als meerdere clients dezelfde verbindingsreeks gebruiken, verifieert de service elke aanmelding. Als 10 gebruikers tegelijkertijd verbinding maken met een database met dezelfde gebruikersnaam en hetzelfde wachtwoord, zijn er 10 gelijktijdige aanmeldingen. Deze limiet geldt alleen voor de duur van de aanmelding en verificatie. Als dezelfde 10 gebruikers opeenvolgend verbinding maken met de database, is het aantal gelijktijdige aanmeldingen nooit groter dan 1.

Maximum aantal sessies

Als u het aantal huidige actieve sessies wilt zien, voert u deze Transact-SQL-query uit op uw database:

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

Als u een SQL Server-workload analyseert, wijzigt u de query zodat deze zich op een specifieke database richt. Deze query helpt u bij het bepalen van de mogelijke sessiebehoeften voor de database als u overweegt deze naar Azure te verplaatsen.

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

Opnieuw retourneren deze query's een aantal punten in de tijd. Als u in de loop van de tijd meerdere voorbeelden verzamelt, hebt u het beste inzicht in uw sessiegebruik.

Queryprestaties bewaken

Trage of langdurige query's kunnen aanzienlijke systeembronnen verbruiken. In deze sectie ziet u hoe u dynamische beheerweergaven gebruikt om enkele veelvoorkomende problemen met queryprestaties te detecteren.

Belangrijkste N-query's zoeken

In het volgende voorbeeld wordt informatie geretourneerd over de vijf belangrijkste query's, gerangschikt op gemiddelde CPU-tijd. In dit voorbeeld worden de query's samengevoegd op basis van hun query-hash, zodat logisch equivalente query's worden gegroepeerd op basis van het cumulatieve resourceverbruik.

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;

Geblokkeerde query's bewaken

Trage of langlopende query's kunnen bijdragen aan overmatig resourceverbruik en kunnen het gevolg zijn van geblokkeerde query's. De oorzaak van de blokkering kan een slecht toepassingsontwerp zijn, slechte queryplannen, het ontbreken van nuttige indexen, enzovoort. U kunt de weergave sys.dm_tran_locks gebruiken om informatie over de huidige vergrendelingsactiviteit in de database op te halen. Zie bijvoorbeeld sys.dm_tran_locks. Zie Azure SQL-blokkeringsproblemen begrijpen en oplossen voor meer informatie over het oplossen van blokkeringsproblemen.

Impasses bewaken

In sommige gevallen kunnen twee of meer query's elkaar blokkeren, wat resulteert in een impasse.

U kunt een database met uitgebreide gebeurtenissen maken om impasse-gebeurtenissen vast te leggen en vervolgens gerelateerde query's en hun uitvoeringsplannen te vinden in Query Store.

Raadpleeg de deadlock-hulpprogramma's in de handleiding Impasses voor Azure SQL Managed Instance.

Queryplannen bewaken

Een inefficiënt queryplan kan ook het CPU-verbruik verhogen. In het volgende voorbeeld wordt de sys.dm_exec_query_stats weergave gebruikt om te bepalen welke query gebruikmaakt van de meest cumulatieve CPU.

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;

Andere bewakingsopties

Bewaken met SQL Insights (preview)

Azure Monitor SQL Insights (preview) is een hulpprogramma voor het bewaken van exemplaren van Azure SQL Managed Instance, databases in Azure SQL Database en SQL Server op Azure SQL-VM's. Deze service maakt gebruik van een externe agent om gegevens uit dynamische beheerweergaven (DMV's) vast te leggen en de gegevens door te sturen naar Azure Log Analytics, waar ze kunnen worden bewaakt en geanalyseerd. U kunt deze gegevens bekijken vanuit Azure Monitor in opgegeven weergaven of de logboekgegevens rechtstreeks openen om query's uit te voeren en trends te analyseren. Zie SQL Insights inschakelen (preview) om aan de slag te gaan met Azure Monitor SQL Insights (preview).

Controleren met Azure Monitor

Azure Monitor biedt diverse groepen, metrische gegevens en eindpunten voor het bewaken van Azure SQL Managed Instance. Zie Azure SQL Managed Instance bewaken met Azure Monitor voor meer informatie. Azure SQL Analytics (preview) is een integratie met Azure Monitor, waarbij veel bewakingsoplossingen niet langer actief zijn in ontwikkeling. Zie Bewaking en prestaties afstemmen in Azure SQL Managed Instance en Azure SQL Database voor meer bewakingsopties.

Zie ook

Volgende stappen