Microsoft SQL Serverで、クエリ/ストアドプロシージャのクエリ実行プランを取得する方法を教えてください。
実行計画を取得する方法はいくつかありますが、使用する方法は状況によって異なります。通常、SQL Server Management Studioを使用して計画を取得できますが、何らかの理由でSQL Server Management Studioでクエリを実行できない場合は、SQL Server Profilerを介して、または検査して計画を取得できると便利です。プランキャッシュ。
SQL Serverには、実行プランを非常に簡単にキャプチャできるいくつかの優れた機能が付属しています。[実際の実行プランを含める]メニュー項目([クエリ]メニューにあります)にチェックを入れて、通常どおりクエリを実行してください。
ストアドプロシージャ内のステートメントの実行プランを取得しようとしている場合は、次のようにストアドプロシージャを実行する必要があります。
exec p_Example 42
クエリが完了すると、結果ウィンドウに「実行計画」というタイトルの追加タブが表示されます。多くのステートメントを実行した場合、このタブに多くのプランが表示される場合があります。
ここから、SQL Server Management Studioで実行プランを検査するか、プランを右クリックして[実行プランに名前を付けて保存...]を選択し、XML形式でファイルにプランを保存します。
この方法は方法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の[実際の実行計画を含める]オプションと同等です。クエリを直接実行できない場合(または、クエリを直接実行したときにクエリの実行が遅くならない場合-クエリの計画のパフォーマンスが悪いことを忘れないでください)、SQL Server Profilerトレースを使用して計画をキャプチャできます。アイデアは、「Showplan」イベントの1つをキャプチャしているトレースの実行中にクエリを実行することです。
負荷に応じてcan本番環境でこのメソッドを使用できますが、明らかに注意が必要です。 SQL Serverプロファイリングメカニズムは、データベースへの影響を最小限に抑えるように設計されていますが、これはanyパフォーマンスへの影響がないという意味ではありません。また、データベースが頻繁に使用されている場合、トレース内の正しい計画のフィルタリングと識別に問題が発生する可能性があります。貴重なデータベースでこれを行うことに満足しているかどうか、DBAに確認してください。
取得する計画は、SQL Server Management Studioの[実際の実行計画を含める]オプションと同等です。
クエリを直接実行できず、プロファイラトレースもキャプチャできない場合でも、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 自体に十分な価値があるトピックです。
すでに掲載されている包括的な回答に加えて、実行計画にプログラム的にアクセスして情報を抽出できると便利です。このためのコード例は以下の通りです。
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
前の回答で説明した方法の他に、無料の実行計画ビューアとクエリ最適化ツール ApexSQL Plan (最近使った)を使用することもできます。
ApexSQLプランをインストールしてSQL Server Management Studioに統合できるため、実行プランはSSMSから直接表示できます。
ApexSQLプランでの推定実行プランの表示
ApexSQLプランでの実際の実行プランの表示
クエリの実際の実行計画を表示するには、前述の2番目の手順から続行します。ただし、推定計画が表示されたら、ApexSQL計画のメインリボンバーから[実際]ボタンをクリックします。
[実績]ボタンをクリックすると、実際の実行計画が他の実行計画データとともにコストパラメータの詳細なプレビューとともに表示されます。
実行計画の表示に関する詳細は、 このリンク をたどって確認できます。
クエリ実行プランを取得して詳細に分析するための私のお気に入りのツールは SQL Sentry Plan Explorer です。それはSSMSよりも実行計画の詳細分析と視覚化のためにはるかにユーザーフレンドリーで、便利でそして包括的です。
以下は、このツールによって提供される機能について理解するためのサンプルスクリーンショットです。
それはツールで利用可能なビューの1つだけです。アプリウィンドウの下部にある一連のタブに注目してください。これにより、さまざまな種類の実行計画の表現と便利な追加情報を取得できます。
さらに、私はその無料版には日常的にそれを使うのを妨げたり、結局はPro版を購入しなければならないという制限があることに気づいていません。あなたが無料版に固執することを好むのであれば、何もあなたがそうすることを禁じません。
更新: (ありがとう Martin Smith )プランエクスプローラは今無料です!詳細については http://www.sqlsentry.com/products/plan-Explorer/sql-server-query-view を参照してください。
クエリプランは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イベントをクリックしてから、グリッドの下にある[クエリプラン]タブをクリックします。これは次のようになります。
EDIT:XEventコードとスクリーンショットはSQL/SSMS 2012 w/SP2から生成されました。SQL2008/R2を使用している場合は、=スクリプトを微調整して作成することができます。しかし、そのバージョンはGUIを持っていないので、あなたはshowplan XMLを抽出し、それを* .sqlplanファイルとして保存してSSMSで開く必要があるでしょう。したがって、SQL 2012以降を使用していない場合は、ここに掲載されている他の回答のいずれかを強くお勧めします。
SQL Server 2016以降から、パフォーマンスを監視するためにクエリストア機能が導入されました。クエリプランの選択とパフォーマンスに関する洞察を提供します。これはトレースイベントや拡張イベントの完全な代替品ではありませんが、バージョンごとに進化するため、将来のリリースで完全に機能するクエリストアがSQL Serverから入手される可能性があります。クエリストアの主な流れ
クエリストアの有効化 :クエリストアはサーバー上のデータベースレベルで機能します。
tempdb
データベースに対してクエリストアを有効にすることはできません。
sys.database_query_store_options
(Transact-SQL)
クエリストアに情報を収集する :クエリストア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以降でのみ使用できます。
これまでに述べたことすべてに加えて、知っておくべき重要なことが1つあります。
クエリプランは、{127レベルの制限のネストされた要素を持つ組み込みのXML列型で表現するには複雑すぎます。これが、 sys.dm_exec_query_plan がNULL
を返す、または以前の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
SQL Server Management Studio(すでに説明済み)の場合と同様に、Datagripでも説明のとおりに使用できます ここ 。
- SQLステートメントを右クリックして、「Explain plan」を選択します。
- [出力]ウィンドウで、[計画]をクリックします。
- デフォルトでは、クエリのツリー表現が表示されます。クエリプランを表示するには、[ビジュアライゼーションの表示]アイコンをクリックするか、Ctrl + Shift + Alt + Uを押します。
実行計画の説明は非常に詳細で時間がかかる場合がありますが、要約すると、クエリの前に「説明」を使用すると、どの部分が最初に実行されたかなど、多くの情報が得られます。これについてもう少し詳しく知りたい場合は、これに関する小さなブログを作成しました。 https://medium.com/swlh/jetbrains-datagrip-explain-plan-ac406772c47