我可以在执行计划窗格中让SSMS向我显示实际查询费用吗?


8

我正在解决SQL Server中多语句存储过程的性能问题。我想知道应该在哪一部分上花费时间。

我从如何阅读查询费用中了解到,它始终是百分比吗?即使SSMS被告知包括实际执行计划,“查询成本(相对于批次)”数字仍基于成本估算,这可能与实际情况相去甚远

测量查询性能中可以了解到:“执行计划查询成本” vs“花费时间”,我可以用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“执行计划”窗格中的对应,依此类推。

但是有更好的方法吗?

Answers:


8

我不知道如何在Management Studio的计划中执行此操作,但这是免费的SentryOne计划资源管理器在您从工具中生成实际计划时将为您执行的众多操作之一-它包括所有每个语句的运行时指标。


哇,看起来很棒。可以肯定的是,Durationand CPU列是实际值而不是估计值,是吗?
AakashM

@AakashM是的,这些是实际值。
亚伦·伯特兰

5

一种好的方法是使用Profiler。在开发或测试箱上设置问题proc的“ repro”,即使用参数对proc进行示例调用。然后,使用Profiler,使用TSQL_SPs模板或从空白模板创建跟踪,添加SP:StmtCompleted事件。添加“持续时间”,“读取”,“写入”和“ CPU”列(如果尚不可用)。将筛选器添加到SPID上的跟踪中(应该从Management Studio中知道)。您也可以在持续时间中添加一个过滤器(例如,大于1000 =大于1秒)。

尽管有开销,您也可以在Profiler中运行跟踪(不要在生产环境中执行此操作),也可以导出定义并创建服务器端跟踪。在专用的开发人员或测试箱上,Profiler的开销并不是很多。

运行该过程并使其完成。您也可能会在此时收集实际执行计划。

停止跟踪并打开文件,您将看到proc的逐行细分,包括每个步骤的时序。我发现这比确定瓶颈的计划有用,尽管该计划在查看相关部分进行调整时会派上用场。

HTH


4

您还可以使用sys.dm_exec_procedure_statssys.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')
    );

这很有用,我一定会在无法安装SQL Sentry Plan Explorer的盒子上使用它。
AakashM
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.