SSMSを取得して、実行プランペインに実際のクエリコストを表示できますか?


8

SQL Serverのマルチステートメントストアドプロシージャのパフォーマンスの問題を修正しています。時間をかけるべき部分を知りたい。

クエリコストの読み取り方法から理解しましたが、それは常にパーセントですか?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.

ステートメントごとに1つの出力メッセージがあります。

「便利」ではありませんが(便利ではありませんが)、時間統計の出力を実行プランペインのステートメントごとの実行プランに関連付けることができSQL Server Execution Timesます。4 番目のメッセージ出力Query 4は、実行プランペインなどに対応します。

しかし、もっと良い方法はありますか?

回答:


8

Management Studioのプランでこれを行う方法はわかりませんが、これは、ツール内から実際のプランを生成するときに無料のSentryOne Plan Explorerが実行する多くの機能の1つです。ステートメントごとのランタイムメトリック。


うわー、これは壮大に見えます。確かに、DurationそしてCPU結果列は推定ではなく実際です、そうですか?
AakashM 2012年

@AakashMはい、それらは実際のものです。
アーロンバートランド

5

これを行う1つの良い方法は、プロファイラーを使用することです。開発ボックスまたはテストボックスで問題のあるプロシージャの「再現」を設定します。つまり、パラメータを使用してプロシージャへのサンプル呼び出しを行います。次に、プロファイラーを使用して、TSQL_SPsテンプレートを使用してトレースを作成するか、空のテンプレートからSP:StmtCompletedイベントを追加します。まだ利用できない場合は、Duration、Reads、Writes、CPU列を追加します。SPIDのトレースにフィルターを追加します(これはManagement Studioから知る必要があります)。フィルターを期間に追加することもできます(たとえば、1000より大きい= 1秒より大きい)。

オーバーヘッドはありますがプロファイラーでトレースを実行するか(プロダクションボックスではこれを行わないでください)、定義をエクスポートしてサーバー側のトレースを作成できます。プロファイラのオーバーヘッドは、専用の開発ボックスやテストボックスではそれほど重要ではありません。

プロシージャを実行して完了させます。この時点で実際の実行計画を収集することもできます。

トレースを停止してファイルを開くと、各ステップのタイミングを含む、プロシージャの行ごとの内訳が表示されます。これは、ボトルネックを特定するための計画よりも有用であると思いますが、調整する関連セクションを見ると計画が重宝します。

HTH


4

sys.dm_exec_procedure_statsおよびsys.dm_exec_query_stats動的管理ビューを使用することもできます。それらの最初のものは、手順全体に関する情報を提供します。2番目は、プロシージャ内の各クエリを分割するために使用できます。以下に例を示します。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.