web-dev-qa-db-ja.com

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

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つの出力メッセージがあります。

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

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

8
AakashM

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

http://sqlsentry.net/plan-Explorer/sql-server-query-view.asp

免責事項:私はSQL Sentryで働いています。

8
Aaron Bertrand

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

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

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

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

HTH

5
wBob

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')
    );
4
Paul White 9