web-dev-qa-db-ja.com

クエリ実行プランを取得する方法

Microsoft SQL Serverで、クエリ/ストアドプロシージャのクエリ実行プランを取得する方法を教えてください。

318
Justin

実行計画を取得する方法はいくつかありますが、使用する方法は状況によって異なります。通常、SQL Server Management Studioを使用して計画を取得できますが、何らかの理由でSQL Server Management Studioでクエリを実行できない場合は、SQL Server Profilerを介して、または検査して計画を取得できると便利です。プランキャッシュ。

方法1-SQL Server Management Studioを使用する

SQL Serverには、実行プランを非常に簡単にキャプチャできるいくつかの優れた機能が付属しています。[実際の実行プランを含める]メニュー項目([クエリ]メニューにあります)にチェックを入れて、通常どおりクエリを実行してください。

Include Action Execution Plan menu item

ストアドプロシージャ内のステートメントの実行プランを取得しようとしている場合は、次のようにストアドプロシージャを実行する必要があります。

exec p_Example 42

クエリが完了すると、結果ウィンドウに「実行計画」というタイトルの追加タブが表示されます。多くのステートメントを実行した場合、このタブに多くのプランが表示される場合があります。

Screenshot of an Execution Plan

ここから、SQL Server Management Studioで実行プランを検査するか、プランを右クリックして[実行プランに名前を付けて保存...]を選択し、XML形式でファイルにプランを保存します。

方法2-SHOWPLANオプションの使用

この方法は方法1と非常に似ています(実際、これはSQL Server Management Studioが内部的に行うことです)が、完全を期すため、またはSQL Server Management Studioを使用できない場合に含めています。

クエリを実行する前に、次のステートメントのoneを実行します。ステートメントはバッチ内の唯一のステートメントでなければなりません。つまり、同時に別のステートメントを実行することはできません。

SET SHOWPLAN_TEXT ON
SET SHOWPLAN_ALL ON
SET SHOWPLAN_XML ON
SET STATISTICS PROFILE ON
SET STATISTICS XML ON -- The is the recommended option to use

これらは接続オプションであるため、接続ごとに1回だけ実行する必要があります。この時点から、実行されるすべてのステートメントは、希望する形式の実行プランを含むadditional resultsetに付随します-通常どおりにクエリを実行します計画を参照してください。

完了したら、次のステートメントでこのオプションをオフにできます。

SET <<option>> OFF

実行計画形式の比較

強い設定がない限り、STATISTICS XMLオプションを使用することをお勧めします。このオプションは、SQL Server Management Studioの[実際の実行計画を含める]オプションと同等で、最も便利な形式でほとんどの情報を提供します。

  • SHOWPLAN_TEXT-クエリを実行せずに、基本的なテキストベースの推定実行計画を表示します
  • SHOWPLAN_ALL-クエリを実行せずに、コスト推定を含むテキストベースの推定実行計画を表示します
  • SHOWPLAN_XML-クエリを実行せずに、XMLベースの推定実行計画とコスト推定を表示します。これは、SQL Server Management Studioの[推定実行プランの表示...]オプションと同等です。
  • STATISTICS PROFILE-クエリを実行し、テキストベースの実際の実行計画を表示します。
  • STATISTICS XML-クエリを実行し、XMLベースの実際の実行計画を表示します。これは、SQL Server Management Studioの[実際の実行計画を含める]オプションと同等です。

方法3-SQL Serverプロファイラーの使用

クエリを直接実行できない場合(または、クエリを直接実行したときにクエリの実行が遅くならない場合-クエリの計画のパフォーマンスが悪いことを忘れないでください)、SQL Server Profilerトレースを使用して計画をキャプチャできます。アイデアは、「Showplan」イベントの1つをキャプチャしているトレースの実行中にクエリを実行することです。

負荷に応じてcan本番環境でこのメソッドを使用できますが、明らかに注意が必要です。 SQL Serverプロファイリングメカニズムは、データベースへの影響を最小限に抑えるように設計されていますが、これはanyパフォーマンスへの影響がないという意味ではありません。また、データベースが頻繁に使用されている場合、トレース内の正しい計画のフィルタリングと識別に問題が発生する可能性があります。貴重なデータベースでこれを行うことに満足しているかどうか、DBAに確認してください。

  1. SQL Server Profilerを開き、トレースを記録する対象のデータベースに接続する新しいトレースを作成します。
  2. [イベントの選択]タブで[すべてのイベントを表示]をチェックし、[パフォーマンス]-> [Showplan XML]の行をチェックして、トレースを実行します。
  3. トレースの実行中に、実行速度の遅いクエリを実行するために必要なことをすべて実行します。
  4. クエリが完了するのを待って、トレースを停止します。
  5. トレースを保存するには、SQL Server Profilerでプランxmlを右クリックし、[イベントデータの抽出...]を選択して、プランをXML形式でファイルに保存します。

取得する計画は、SQL Server Management Studioの[実際の実行計画を含める]オプションと同等です。

方法4-クエリキャッシュの検査

クエリを直接実行できず、プロファイラトレースもキャプチャできない場合でも、SQLクエリプランキャッシュを調べることで推定プランを取得できます。

SQL Server DMVs をクエリすることにより、プランキャッシュを検査します。以下は、すべてのキャッシュされたクエリプランを(xmlとして)SQLテキストと共にリストする基本的なクエリです。ほとんどのデータベースでは、追加のフィルタリング句を追加して、関心のある計画だけに結果をフィルタリングする必要があります。

SELECT UseCounts, Cacheobjtype, Objtype, TEXT, query_plan
FROM sys.dm_exec_cached_plans 
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
CROSS APPLY sys.dm_exec_query_plan(plan_handle)

このクエリを実行し、プランXMLをクリックして、新しいウィンドウでプランを開きます。右クリックして[実行プランに名前を付けて保存...]を選択し、プランをXML形式でファイルに保存します。

ノート:

非常に多くの要因が関係しているため(テーブルとインデックススキーマから保存されたデータ、テーブル統計まで)、常にalwaysを取得してください関心のあるデータベースからの実行計画(通常はパフォーマンスの問題が発生しているもの)。

暗号化されたストアドプロシージャの実行計画をキャプチャすることはできません。

「実際の」実行計画と「推定された」実行計画

actual実行計画は、SQL Serverが実際にクエリを実行するものです。一方、推定実行計画SQL Serverは、何を実行しますかwould実行せずに実行しますクエリ。論理的には同等ですが、実際の実行計画は、クエリの実行時に実際に何が起こったのかについての追加の詳細と統計が含まれているため、はるかに役立ちます。これは、SQL Serverの推定がオフになっている問題を診断する場合(統計が古い場合など)に不可欠です。

クエリ実行プランを解釈するにはどうすればよいですか?

これは、(無料の) book 自体に十分な価値があるトピックです。

こちらもご覧ください:

486
Justin

すでに掲載されている包括的な回答に加えて、実行計画にプログラム的にアクセスして情報を抽出できると便利です。このためのコード例は以下の通りです。

DECLARE @TraceID INT
EXEC StartCapture @@SPID, @TraceID OUTPUT
EXEC sp_help 'sys.objects' /*<-- Call your stored proc of interest here.*/
EXEC StopCapture @TraceID

StartCaptureの定義

CREATE PROCEDURE StartCapture
@Spid INT,
@TraceID INT OUTPUT
AS
DECLARE @maxfilesize BIGINT = 5
DECLARE @filepath NVARCHAR(200) = N'C:\trace_' + LEFT(NEWID(),36)

EXEC sp_trace_create @TraceID OUTPUT, 0, @filepath, @maxfilesize, NULL 

exec sp_trace_setevent @TraceID, 122, 1, 1
exec sp_trace_setevent @TraceID, 122, 22, 1
exec sp_trace_setevent @TraceID, 122, 34, 1
exec sp_trace_setevent @TraceID, 122, 51, 1
exec sp_trace_setevent @TraceID, 122, 12, 1
-- filter for spid
EXEC sp_trace_setfilter @TraceID, 12, 0, 0, @Spid
-- start the trace
EXEC sp_trace_setstatus @TraceID, 1

StopCaptureの定義

CREATE  PROCEDURE StopCapture
@TraceID INT
AS
WITH  XMLNAMESPACES ('http://schemas.Microsoft.com/sqlserver/2004/07/showplan' as sql), 
      CTE
     as (SELECT CAST(TextData AS VARCHAR(MAX)) AS TextData,
                ObjectID,
                ObjectName,
                EventSequence,
                /*costs accumulate up the tree so the MAX should be the root*/
                MAX(EstimatedTotalSubtreeCost) AS EstimatedTotalSubtreeCost
         FROM   fn_trace_getinfo(@TraceID) fn
                CROSS APPLY fn_trace_gettable(CAST(value AS NVARCHAR(200)), 1)
                CROSS APPLY (SELECT CAST(TextData AS XML) AS xPlan) x
                CROSS APPLY (SELECT T.relop.value('@EstimatedTotalSubtreeCost',
                                            'float') AS EstimatedTotalSubtreeCost
                             FROM   xPlan.nodes('//sql:RelOp') T(relop)) ca
         WHERE  property = 2
                AND TextData IS NOT NULL
                AND ObjectName not in ( 'StopCapture', 'fn_trace_getinfo' )
         GROUP  BY CAST(TextData AS VARCHAR(MAX)),
                   ObjectID,
                   ObjectName,
                   EventSequence)
SELECT ObjectName,
       SUM(EstimatedTotalSubtreeCost) AS EstimatedTotalSubtreeCost
FROM   CTE
GROUP  BY ObjectID,
          ObjectName  

-- Stop the trace
EXEC sp_trace_setstatus @TraceID, 0
-- Close and delete the trace
EXEC sp_trace_setstatus @TraceID, 2
GO
40
Martin Smith

Microsoft SQL Server Management Studioを使用しているとします。

  • 推定クエリプラン の場合は、 Ctrl + L または次のボタンを押すことができます。

enter image description here

  • 実際のクエリプラン の場合、クエリを実行する前に Ctrl + M または次のボタンを押すことができます。

enter image description here

  • Live Query Plan の場合(SSMS 2016のみ)、クエリを実行する前に次のボタンを使用してください。

enter image description here

17
Tigerjz32

前の回答で説明した方法の他に、無料の実行計画ビューアとクエリ最適化ツール ApexSQL Plan (最近使った)を使用することもできます。

ApexSQLプランをインストールしてSQL Server Management Studioに統合できるため、実行プランはSSMSから直接表示できます。

ApexSQLプランでの推定実行プランの表示

  1. SSMSで New Query ボタンをクリックし、クエリテキストをクエリテキストウィンドウに貼り付けます。右クリックして、コンテキストメニューから[推定実行計画の表示]オプションを選択します。

New Query button in SSMS

  1. 実行計画図は、結果セクションの「実行計画」タブに表示されます。次に実行計画を右クリックして、コンテキストメニューで[ApexSQL計画で開く]オプションを選択します。

Execution Plan

  1. 推定実行計画はApexSQL計画で開かれ、クエリ最適化のために分析できます。

Estimated execution plan

ApexSQLプランでの実際の実行プランの表示

クエリの実際の実行計画を表示するには、前述の2番目の手順から続行します。ただし、推定計画が表示されたら、ApexSQL計画のメインリボンバーから[実際]ボタンをクリックします。

click the “Actual” button from the main ribbon bar

[実績]ボタンをクリックすると、実際の実行計画が他の実行計画データとともにコストパラメータの詳細なプレビューとともに表示されます。

Actual execution plan

実行計画の表示に関する詳細は、 このリンク をたどって確認できます。

15
Marcin Czyz

クエリ実行プランを取得して詳細に分析するための私のお気に入りのツールは SQL Sentry Plan Explorer です。それはSSMSよりも実行計画の詳細分析と視覚化のためにはるかにユーザーフレンドリーで、便利でそして包括的です。

以下は、このツールによって提供される機能について理解するためのサンプルスクリーンショットです。

SQL Sentry Plan Explorer window screen shot

それはツールで利用可能なビューの1つだけです。アプリウィンドウの下部にある一連のタブに注目してください。これにより、さまざまな種類の実行計画の表現と便利な追加情報を取得できます。

さらに、私はその無料版には日常的にそれを使うのを妨げたり、結局はPro版を購入しなければならないという制限があることに気づいていません。あなたが無料版に固執することを好むのであれば、何もあなたがそうすることを禁じません。

更新: (ありがとう Martin Smith )プランエクスプローラは今無料です!詳細については http://www.sqlsentry.com/products/plan-Explorer/sql-server-query-view を参照してください。

13

クエリプランはquery_post_execution_showplanイベントを介してExtended Eventsセッションから取得できます。これがXEventセッションのサンプルです。

/*
    Generated via "Query Detail Tracking" template.
*/
CREATE EVENT SESSION [GetExecutionPlan] ON SERVER 
ADD EVENT sqlserver.query_post_execution_showplan(
    ACTION(package0.event_sequence,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)),

/* Remove any of the following events (or include additional events) as desired. */
ADD EVENT sqlserver.error_reported(
    ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
    WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.module_end(SET collect_statement=(1)
    ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
    WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.rpc_completed(
    ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
    WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.sp_statement_completed(SET collect_object_name=(1)
    ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
    WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.sql_batch_completed(
    ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
    WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.sql_statement_completed(
    ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.database_id,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack)
    WHERE ([package0].[greater_than_uint64]([sqlserver].[database_id],(4)) AND [package0].[equal_boolean]([sqlserver].[is_system],(0)))) 
ADD TARGET package0.ring_buffer
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)
GO

セッションを作成した後(SSMSで)、オブジェクトエクスプローラーに移動して、管理|詳細について調べます。拡張イベントセッション「GetExecutionPlan」セッションを右クリックして起動します。もう一度右クリックして[ライブデータの視聴]を選択します。

次に、新しいクエリウィンドウを開き、1つ以上のクエリを実行します。これがAdventureWorksのものです。

USE AdventureWorks;
GO

SELECT p.Name AS ProductName, 
    NonDiscountSales = (OrderQty * UnitPrice),
    Discounts = ((OrderQty * UnitPrice) * UnitPriceDiscount)
FROM Production.Product AS p 
INNER JOIN Sales.SalesOrderDetail AS sod
    ON p.ProductID = sod.ProductID 
ORDER BY ProductName DESC;
GO

しばらくすると、[GetExecutionPlan:Live Data]タブに結果が表示されます。グリッド内のいずれかのquery_post_execution_showplanイベントをクリックしてから、グリッドの下にある[クエリプラン]タブをクリックします。これは次のようになります。

enter image description here

EDIT:XEventコードとスクリーンショットはSQL/SSMS 2012 w/SP2から生成されました。SQL2008/R2を使用している場合は、=スクリプトを微調整して作成することができます。しかし、そのバージョンはGUIを持っていないので、あなたはshowplan XMLを抽出し、それを* .sqlplanファイルとして保存してSSMSで開く必要があるでしょう。したがって、SQL 2012以降を使用していない場合は、ここに掲載されている他の回答のいずれかを強くお勧めします。

7
Dave Mason

SQL Server 2016以降から、パフォーマンスを監視するためにクエリストア機能が導入されました。クエリプランの選択とパフォーマンスに関する洞察を提供します。これはトレースイベントや拡張イベントの完全な代替品ではありませんが、バージョンごとに進化するため、将来のリリースで完全に機能するクエリストアがSQL Serverから入手される可能性があります。クエリストアの主な流れ

  1. SQL Serverの既存のコンポーネントは、クエリストアマネージャを利用してクエリストアと対話します。
  2. Query Store Managerは、どのStoreを使用すべきかを決定し、次いで実行をそのストアに渡す(計画またはランタイム統計またはクエリ待ち統計)
    • プランストア - 実行プラン情報を永続化する
    • ランタイム統計ストア - 実行統計情報の永続化
    • 待機統計ストアの照会 - 待機統計情報を永続化します。
  3. 計画、実行時間統計、待機ストアは、SQL Serverの拡張機能としてクエリストアを使用します。

enter image description here

  1. クエリストアの有効化 :クエリストアはサーバー上のデータベースレベルで機能します。

    • デフォルトでは、クエリストアは新しいデータベースに対してアクティブではありません。
    • Masterデータベースまたはtempdbデータベースに対してクエリストアを有効にすることはできません。
    • 入手可能なDMV

      sys.database_query_store_options (Transact-SQL)

  2. クエリストアに情報を収集する :クエリストアDMV(Data Management Views)を使用して、3つのストアから利用可能なすべての情報を収集します。

    • クエリプランストア: 実行プラン情報を保持し、クエリのコンパイルに関連するすべての情報を取得する責任があります。

      sys.query_store_query (Transact-SQL) sys.query_store_plan (Transact-SQL) sys.query_store_query_text (Transact-SQL)

    • ランタイム統計ストア: 実行統計情報を保持し、おそらく最も頻繁に更新されるストアです。これらの統計は、クエリ実行データを表します。

      sys.query_store_runtime_stats (Transact-SQL)

    • 待機統計ストアの照会: 待機統計情報の保持と取得。

      sys.query_store_wait_stats (Transact-SQL)

注: [クエリ待機統計ストア]は、SQL Server 2017以降でのみ使用できます。

5
vCillusion

これまでに述べたことすべてに加えて、知っておくべき重要なことが1つあります。

クエリプランは、{127レベルの制限のネストされた要素を持つ組み込みのXML列型で表現するには複雑すぎます。これが、 sys.dm_exec_query_planNULLを返す、または以前のMS SQLバージョンでエラーをスローすることがある理由の1つなので、一般的に sys.dm_exec_text_query_plan を使用する方が安全です。後者には、バッチ全体ではなく特定のステートメントの計画を選択するという便利な機能もあります。これを使用して、現在実行中のステートメントの計画を表示します。

SELECT p.query_plan
FROM sys.dm_exec_requests AS r
OUTER APPLY sys.dm_exec_text_query_plan(
                r.plan_handle,
                r.statement_start_offset,
                r.statement_end_offset) AS p

結果のテーブルのテキスト列は、XML列に比べてあまり便利ではありません。内容をファイルに保存しなくても、結果をクリックして別のタブでダイアグラムとして開くことができるようにするには、ちょっとしたトリックを使用できます(単にCAST(... AS XML)を使用することはできません)。単一行

SELECT Tag = 1, Parent = NULL, [ShowPlanXML!1!!XMLTEXT] = query_plan
FROM sys.dm_exec_text_query_plan(
                -- set these variables or copy values
                -- from the results of the above query
                @plan_handle,
                @statement_start_offset,
                @statement_end_offset)
FOR XML EXPLICIT
3
alkoln

SQL Server Management Studio(すでに説明済み)の場合と同様に、Datagripでも説明のとおりに使用できます ここ

  1. SQLステートメントを右クリックして、「Explain plan」を選択します。
  2. [出力]ウィンドウで、[計画]をクリックします。
  3. デフォルトでは、クエリのツリー表現が表示されます。クエリプランを表示するには、[ビジュアライゼーションの表示]アイコンをクリックするか、Ctrl + Shift + Alt + Uを押します。
2
Daan

実行計画の説明は非常に詳細で時間がかかる場合がありますが、要約すると、クエリの前に「説明」を使用すると、どの部分が最初に実行されたかなど、多くの情報が得られます。これについてもう少し詳しく知りたい場合は、これに関する小さなブログを作成しました。 https://medium.com/swlh/jetbrains-datagrip-explain-plan-ac406772c47

0
Abd Rmdn