Published on

January 25, 2017

Como encontrar as consultas TSQL com pior desempenho no SQL Server

Você já se perguntou como encontrar as consultas TSQL com pior desempenho em sua instância do SQL Server? Se sim, você não está sozinho. No SQL Server, as estatísticas de consulta são mantidas à medida que os comandos TSQL são executados. Essas estatísticas de consulta podem ser acessadas usando os Objetos de Gerenciamento Dinâmico fornecidos pelo SQL Server.

O Objeto de Gerenciamento Dinâmico sys.dm_exec_query_stats retorna uma visão das estatísticas de consulta que o SQL Server está mantendo atualmente. Essas estatísticas são armazenadas na memória juntamente com o plano em cache para cada consulta. Enquanto um plano de execução TSQL estiver armazenado no cache de plano, você pode recuperar as estatísticas para esse comando TSQL. No entanto, uma vez que o comando é removido do cache de procedimento, as estatísticas também são descartadas.

Abaixo está um exemplo de um procedimento armazenado que pode ser usado para recuperar as estatísticas de consulta TSQL armazenadas no cache de procedimento:

CREATE PROCEDURE [dbo].[usp_Worst_TSQL]
    @DBNAME VARCHAR(128) = '',
    @COUNT INT = 999999999,
    @ORDERBY VARCHAR(4) = 'TCPU'
AS
BEGIN
    -- Verificar se o parâmetro @ORDERBY é válido
    IF ((SELECT CASE WHEN @ORDERBY IN ('ACPU', 'TCPU', 'AE', 'TE', 'EC', 'AIO', 'TIO', 'ALR', 'TLR', 'ALW', 'TLW', 'APR', 'TPR') THEN 1 ELSE 0 END) = 0)
    BEGIN
        -- Abortar se o parâmetro @ORDERBY for inválido
        RAISERROR('@ORDERBY parâmetro não é APCU, TCPU, AE, TE, EC, AIO, TIO, ALR, TLR, ALW, TLW, APR ou TPR', 11, 1)
        RETURN
    END

    SELECT TOP (@COUNT)
        COALESCE(DB_NAME(st.dbid), DB_NAME(CAST(pa.value AS INT)) + '*', 'Recurso') AS [Nome do Banco de Dados],
        SUBSTRING(text, CASE WHEN statement_start_offset = 0 OR statement_start_offset IS NULL THEN 1 ELSE statement_start_offset / 2 + 1 END,
            CASE WHEN statement_end_offset = 0 OR statement_end_offset = -1 OR statement_end_offset IS NULL THEN LEN(text) ELSE statement_end_offset / 2 END
                - CASE WHEN statement_start_offset = 0 OR statement_start_offset IS NULL THEN 1 ELSE statement_start_offset / 2 END + 1) AS [Instrução],
        OBJECT_SCHEMA_NAME(st.objectid, dbid) AS [Nome do Esquema],
        OBJECT_NAME(st.objectid, dbid) AS [Nome do Objeto],
        objtype AS [Tipo de Plano em Cache],
        total_elapsed_time / execution_count AS [Tempo Médio Decorrido],
        execution_count AS [Contagem de Execução],
        (total_logical_reads + total_logical_writes + total_physical_reads) / execution_count AS [Média de E/S],
        total_logical_reads + total_logical_writes + total_physical_reads AS [Total de E/S],
        total_logical_reads / execution_count AS [Média de Leituras Lógicas],
        total_logical_reads AS [Total de Leituras Lógicas],
        total_logical_writes / execution_count AS [Média de Gravações Lógicas],
        total_logical_writes AS [Total de Gravações Lógicas],
        total_physical_reads / execution_count AS [Média de Leituras Físicas],
        total_physical_reads AS [Total de Leituras Físicas],
        total_worker_time / execution_count AS [Média de CPU],
        total_worker_time AS [Total de CPU],
        total_elapsed_time AS [Tempo Total Decorrido],
        last_execution_time AS [Último Horário de Execução]
    FROM sys.dm_exec_query_stats qs
    JOIN sys.dm_exec_cached_plans cp ON qs.plan_handle = cp.plan_handle
    CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) st
    OUTER APPLY sys.dm_exec_plan_attributes(qs.plan_handle) pa
    WHERE attribute = 'dbid'
        AND CASE WHEN @DBNAME = '' THEN ''
                 ELSE COALESCE(DB_NAME(st.dbid), DB_NAME(CAST(pa.value AS INT)) + '*', 'Recurso') END
            IN (RTRIM(@DBNAME), RTRIM(@DBNAME) + '*')
    ORDER BY CASE WHEN @ORDERBY = 'ACPU' THEN total_worker_time / execution_count
                  WHEN @ORDERBY = 'TCPU' THEN total_worker_time
                  WHEN @ORDERBY = 'AE' THEN total_elapsed_time / execution_count
                  WHEN @ORDERBY = 'TE' THEN total_elapsed_time
                  WHEN @ORDERBY = 'EC' THEN execution_count
                  WHEN @ORDERBY = 'AIO' THEN (total_logical_reads + total_logical_writes + total_physical_reads) / execution_count
                  WHEN @ORDERBY = 'TIO' THEN total_logical_reads + total_logical_writes + total_physical_reads
                  WHEN @ORDERBY = 'ALR' THEN total_logical_reads / execution_count
                  WHEN @ORDERBY = 'TLR' THEN total_logical_reads
                  WHEN @ORDERBY = 'ALW' THEN total_logical_writes / execution_count
                  WHEN @ORDERBY = 'TLW' THEN total_logical_writes
                  WHEN @ORDERBY = 'APR' THEN total_physical_reads / execution_count
                  WHEN @ORDERBY = 'TPR' THEN total_physical_reads
             END DESC
END

Este procedimento armazenado pode receber diferentes parâmetros para determinar quais estatísticas são retornadas e como os dados são ordenados. O parâmetro @DBNAME é usado para restringir a saída a um banco de dados específico. Se este parâmetro for definido como um nome de banco de dados específico, apenas as instruções associadas a esse banco de dados serão exibidas. Se o parâmetro @DBNAME não for definido, o procedimento armazenado retornará linhas associadas a qualquer banco de dados.

O parâmetro @COUNT permite controlar o número de linhas retornadas pelo procedimento armazenado. Se este parâmetro for usado, apenas as primeiras x linhas (onde x é igual a @COUNT) serão retornadas, com base no parâmetro @ORDERBY.

O parâmetro @ORDERBY identifica a ordem de classificação das linhas retornadas em ordem decrescente. Ele suporta os seguintes tipos: CPU, AE, TE, EC, AIO, TIO, ALR, TLR, ALW, TLW, APR e TPR. Por exemplo, se você deseja exibir as 6 principais instruções no banco de dados AdventureWorks com base no uso médio de CPU, você pode executar o procedimento armazenado da seguinte forma:

EXEC usp_Worst_TSQL @DBNAME='AdventureWorks', @COUNT=6, @ORDERBY='ACPU';

Da mesma forma, você pode recuperar as 100 principais instruções ordenadas por E/S média:

EXEC usp_Worst_TSQL @COUNT=100, @ORDERBY='AE';

Se você deseja mostrar todas as instruções ordenadas por E/S média, você pode simplesmente executar o procedimento armazenado sem nenhum parâmetro:

EXEC usp_Worst_TSQL;

Ao usar este procedimento armazenado, você poderá identificar e analisar as consultas TSQL com pior desempenho em sua instância ou banco de dados do SQL Server, com base em várias métricas de desempenho, como uso de CPU, contagem de execução, E/S e tempo decorrido.

Veja todos os artigos de Greg Larsen

Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.