Могу ли я заставить SSMS показывать мне фактическую стоимость запроса на панели плана выполнения?

8

Я исправляю проблемы с производительностью хранимой процедуры с несколькими состояниями в SQL Server. Я хочу знать, на какие части я должен тратить время.

Я понимаю, как читать Query Cost, и всегда ли это процент? что даже когда SSMS предписано включить фактический план выполнения , показатели «Стоимость запроса (относительно пакета)» все еще основаны на оценочных значениях , которые могут быть далеки от фактических

Из измерения производительности запросов: «Стоимость запроса плана выполнения» и «Время, затраченное на выполнение» я понимаю, что я могу окружить вызов хранимой процедуры SET STATISTICS TIMEинструкциями, и тогда я получу такой список на Messagesпанели:

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 1 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

[etc]

 SQL Server Execution Times:
   CPU time = 187 ms,  elapsed time = 206 ms.

с одним выходным сообщением для каждого оператора.

Я могу «легко» (хотя и не удобно) связать вывод статистики времени с планами выполнения «оператор за оператором» на панели плана выполнения, посчитав их: четвертый SQL Server Execution Timesвывод сообщения соответствует на Query 4панели плана выполнения и т. Д.

Но есть ли лучший способ?

AakashM
источник

Ответы:

8

Я не знаю, как сделать это в плане из Management Studio, но это одна из многих вещей, которые бесплатный SentryOne Plan Explorer сделает для вас, когда вы создадите фактический план из инструмента - он включает в себя все метрики времени выполнения на оператор.

Аарон Бертран
источник
Вау, это выглядит великолепно. Я уверен, что столбцы Durationи CPUрезультаты являются фактическими, а не оценочными значениями, да?
AakashM
@ AakashM да, это факт.
Аарон Бертран
5

Один хороший способ сделать это с помощью Profiler. Установите «repro» вашего проблемного процесса на dev или test box, то есть пример вызова процесса с параметрами. Затем с помощью Profiler создайте трассировку, используя либо шаблон TSQL_SPs, либо из пустого шаблона добавьте событие SP: StmtCompleted. Добавьте столбцы Длительность, Чтение, Запись и ЦП, если они еще не доступны. Добавьте фильтр в трассировку вашего SPID (который вы должны знать из Management Studio). Вы также можете добавить фильтр к длительности (например, больше 1000 = больше 1 секунды).

Вы можете либо запустить трассировку в Профилировщике, хотя есть издержки (НЕ делайте этого на производственной коробке), либо экспортировать определение и создать трассировку на стороне сервера. Издержки Profiler не так важны для выделенного разработчика или тестового бокса.

Запустите процесс и дайте ему завершить. Вы также можете получить план фактического выполнения на данном этапе.

Остановите свою трассировку и откройте файл, и вы должны увидеть построчную разбивку вашего процесса, включая время для каждого шага. Я нахожу это более полезным, чем план по выявлению узких мест, хотя этот план пригодится при рассмотрении соответствующих разделов для настройки.

НТН

wBob
источник
4

Вы также можете использовать динамические административные представления sys.dm_exec_procedure_stats и sys.dm_exec_query_stats . Первый из них дает информацию о процедуре в целом; вторая может использоваться для разбивки каждого запроса в процедуре. Пример показан ниже:

USE AdventureWorks;
GO
CREATE PROCEDURE dbo.Test
    @NameLike nvarchar(50)
AS
BEGIN
    SELECT
        ProductCount = COUNT_BIG(*)
    FROM Production.Product AS p
    JOIN Production.TransactionHistory AS th ON
        th.ProductID = p.ProductID
    WHERE
        p.Name LIKE @NameLike;

    SELECT
        pc.Name,
        ProductCount = COUNT_BIG(*)
    FROM Production.Product AS p
    JOIN Production.ProductSubcategory AS ps ON
        ps.ProductSubcategoryID = p.ProductSubcategoryID
    JOIN Production.ProductCategory AS pc ON
        pc.ProductCategoryID = ps.ProductCategoryID
    WHERE
        p.Name LIKE @NameLike
    GROUP BY
        pc.Name
    ORDER BY
        pc.Name;
END;
GO
EXECUTE dbo.Test @NameLike = N'A%';
EXECUTE dbo.Test @NameLike = N'F%';

Процедура статистики:

SELECT
    deps.last_execution_time,
    deps.last_worker_time,
    deps.last_physical_reads,
    deps.last_logical_writes,
    deps.last_logical_reads,
    deps.last_elapsed_time
FROM sys.dm_exec_procedure_stats AS deps
WHERE
    deps.database_id = DB_ID()
    AND deps.[object_id] = OBJECT_ID(N'dbo.Test', N'P');

Запросы в рамках процедуры:

SELECT
    query.the_text,
    deqs.last_execution_time,
    deqs.last_worker_time,
    deqs.last_physical_reads,
    deqs.last_logical_writes,
    deqs.last_logical_reads,
    deqs.last_clr_time,
    deqs.last_elapsed_time,
    deqs.last_rows    -- note: Only present from 2008 R2 onwards
FROM sys.dm_exec_query_stats AS deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.[sql_handle]) AS dest
CROSS APPLY
(
    VALUES 
    (
        SUBSTRING
        (
            dest.[text], 
            deqs.statement_start_offset / 2 + 1,
            (ISNULL(NULLIF(deqs.statement_end_offset, -1), DATALENGTH(dest.[text])) - deqs.statement_start_offset) / 2 + 1
        )
    )
) AS query (the_text)
WHERE
    deqs.[sql_handle] IN
    (
        SELECT
            deps.[sql_handle]
        FROM sys.dm_exec_procedure_stats AS deps
        WHERE
            deps.database_id = DB_ID()
            AND deps.[object_id] = OBJECT_ID(N'dbo.Test', N'P')
    );
Пол Уайт 9
источник
Это полезно, и я определенно буду использовать это на боксах, где я не могу установить SQL Sentry Plan Explorer.
AakashM