在Microsoft SQL Server如何获得查询/存储过程的查询执行计划?


有许多获得执行计划的方法,使用哪一种取决于你的情况。通常你可以使用SQL Server Management Studio来获得一个计划,但是如果由于某种原因你不能在SQL Server Management Studio中运行你的查询,那么你可能会发现通过SQL Server Profiler或检查计划缓存来获得一个计划是有帮助的。

方法1 -使用SQL Server Management Studio

SQL Server提供了一些简洁的功能,可以很容易地捕获执行计划,只需确保选中“包含实际执行计划”菜单项(在“查询”菜单下找到),并正常运行查询即可。

如果你试图获取存储过程中语句的执行计划,那么你应该执行存储过程,如下所示:

exec p_Example 42

当您的查询完成时,您应该在结果窗格中看到一个名为“执行计划”的额外选项卡。如果您运行了许多语句,那么您可能会在这个选项卡中看到许多计划。

从这里,您可以在SQL Server Management Studio中查看执行计划,或者右键单击计划并选择“另存执行计划为…”,将计划保存为XML格式的文件。

方法2 -使用SHOWPLAN选项

此方法与方法1非常相似(实际上,这是SQL Server Management Studio内部所做的),但是为了完整起见,或者如果您没有可用的SQL Server Management Studio,我将其包括在内。

在运行查询之前,运行以下语句之一。该语句必须是批处理中唯一的语句,即不能同时执行另一条语句:

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

这些是连接选项,因此每个连接只需要运行一次。从这一点开始,所有运行的语句都将附带一个附加的结果集,其中包含所需格式的执行计划-只需像正常情况下那样运行查询就可以看到计划。

一旦你完成了,你可以用下面的语句关闭这个选项:

SET <<option>> OFF

执行计划格式的比较

除非您有强烈的偏好,否则我建议使用STATISTICS XML选项。该选项相当于SQL Server Management Studio中的“包含实际执行计划”选项,以最方便的格式提供最多的信息。

SHOWPLAN_TEXT - Displays a basic text based estimated execution plan, without executing the query SHOWPLAN_ALL - Displays a text based estimated execution plan with cost estimations, without executing the query SHOWPLAN_XML - Displays an XML based estimated execution plan with cost estimations, without executing the query. This is equivalent to the "Display Estimated Execution Plan..." option in SQL Server Management Studio. STATISTICS PROFILE - Executes the query and displays a text based actual execution plan. STATISTICS XML - Executes the query and displays an XML based actual execution plan. This is equivalent to the "Include Actual Execution Plan" option in SQL Server Management Studio.

方法3 -使用SQL Server分析器

如果你不能直接运行你的查询(或者你的查询在你直接执行它的时候运行得不慢——记住我们想要一个执行糟糕的查询计划),那么你可以使用SQL Server Profiler跟踪来捕获一个计划。其思想是在捕获“Showplan”事件之一的跟踪运行时运行查询。

Note that depending on load you can use this method on a production environment, however you should obviously use caution. The SQL Server profiling mechanisms are designed to minimize impact on the database but this doesn't mean that there won't be any performance impact. You may also have problems filtering and identifying the correct plan in your trace if your database is under heavy use. You should obviously check with your DBA to see if they are happy with you doing this on their precious database!

Open SQL Server Profiler and create a new trace connecting to the desired database against which you wish to record the trace. Under the "Events Selection" tab check "Show all events", check the "Performance" -> "Showplan XML" row and run the trace. While the trace is running, do whatever it is you need to do to get the slow running query to run. Wait for the query to complete and stop the trace. To save the trace right click on the plan xml in SQL Server Profiler and select "Extract event data..." to save the plan to file in XML format.

你得到的计划相当于SQL Server Management Studio中的“包含实际执行计划”选项。

方法4 -检查查询缓存

如果不能直接运行查询,也不能捕获分析器跟踪,那么仍然可以通过检查SQL查询计划缓存来获得估计的计划。

我们通过查询SQL Server dmv来检查计划缓存。下面是一个基本查询,它将列出所有缓存的查询计划(以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,在新窗口中打开计划-右键单击并选择“Save execution plan as…”,以XML格式将计划保存为文件。

注:

因为涉及到很多因素(从表和索引模式到存储的数据和表统计信息),所以应该始终尝试从您感兴趣的数据库(通常是遇到性能问题的数据库)获取执行计划。

无法捕获加密存储过程的执行计划。

“实际”和“估计”执行计划

实际执行计划是指SQL Server实际运行查询的计划,而预估执行计划则是指SQL Server在不执行查询的情况下会做什么。尽管逻辑上是等价的,但实际的执行计划更有用,因为它包含执行查询时实际发生的情况的额外细节和统计信息。这在诊断SQL server估计错误的问题(例如统计数据过期)时非常重要。

预估和实际执行计划重审

如何解释查询执行计划?

这是一个值得写一本(免费)书的主题。

参见:

执行计划基础知识 SHOWPLAN权限和Transact-SQL批处理 SQL Server 2008 -使用查询哈希和查询计划哈希 分析SQL Server计划缓存


除了已经发布的综合答案之外,有时能够以编程方式访问执行计划以提取信息也是有用的。下面是示例代码。

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

停止捕获定义

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

我最喜欢的获取和深入分析查询执行计划的工具是SQL Sentry Plan Explorer。它在执行计划的细节分析和可视化方面比SSMS更加人性化、方便和全面。

下面是一个示例屏幕截图,让你了解这个工具提供了什么功能:

它只是工具中可用的视图之一。注意应用程序窗口底部的一组选项卡,它可以让你获得不同类型的执行计划表示以及有用的附加信息。

此外,我还没有发现它的免费版有任何限制,会阻止你每天使用它,或者迫使你最终购买专业版。所以,如果你更喜欢使用免费版,没有什么能阻止你这么做。


查询计划可以通过query_post_execution_showplan事件从扩展事件会话中获得。下面是一个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”会话并启动它。再次右键选择“观看实时数据”。

接下来,打开一个新的查询窗口并运行一个或多个查询。以下是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事件之一,然后单击网格下面的“Query Plan”选项卡。它应该看起来像这样:

编辑:XEvent代码和屏幕截图是从SQL/SSMS 2012 w/ SP2生成的。如果您使用的是SQL 2008/R2,则可以调整脚本以使其运行。但那个版本没有GUI,所以你需要提取showplan XML,保存为*。并在SSMS中打开。这是麻烦的。XEvents在SQL 2005或更早的版本中并不存在。所以,如果你没有使用SQL 2012或更高版本,我强烈建议你使用这里发布的其他答案之一。


假设您正在使用Microsoft SQL Server Management Studio

对于估计的查询计划,可以按Ctrl + L或以下按钮。

对于“实际查询计划”,可以按“Ctrl +” M或以下按钮,然后执行查询。

对于实时查询计划,(仅在SSMS 2016中)在执行查询之前使用以下按钮。


除了前面回答中描述的方法外,您还可以使用免费的执行计划查看器和查询优化工具ApexSQL plan(我最近碰到了它)。

您可以将ApexSQL计划安装并集成到SQL Server Management Studio中,因此可以直接从SSMS查看执行计划。

在“ApexSQL计划”中查看估计的执行计划

单击SSMS中的新建查询按钮,并将查询文本粘贴到查询文本窗口中。右击并从上下文菜单中选择“Display Estimated Execution Plan”选项。

执行计划图将显示在结果部分的execution plan选项卡中。接下来右键单击执行计划,在上下文菜单中选择“在ApexSQL计划中打开”选项。

预估执行计划将在ApexSQL plan中打开,可以对其进行分析以进行查询优化。

在“ApexSQL计划”中查看实际执行计划

要查看查询的实际执行计划,从前面提到的第二步继续,但是现在,一旦估计计划显示出来,在ApexSQL计划的主带栏中单击“实际”按钮。

一旦点击“实际”按钮,实际执行计划将显示详细的成本参数预览以及其他执行计划数据。

点击此链接可以找到有关查看执行计划的更多信息。


从SQL Server 2016+开始,引入了查询存储功能来监控性能。它提供了对查询计划选择和性能的洞察。 它并不是跟踪或扩展事件的完全替代,但随着它从一个版本到另一个版本的发展,我们可能会在SQL Server的未来版本中得到一个功能齐全的查询存储。 查询存储的主要流程

SQL Server existing components interact with query store by utilising Query Store Manager. Query Store Manager determines which Store should be used and then passes execution to that store (Plan or Runtime Stats or Query Wait Stats) Plan Store - Persisting the execution plan information Runtime Stats Store - Persisting the execution statistics information Query Wait Stats Store - Persisting wait statistics information. Plan, Runtime Stats and Wait store uses Query Store as an extension to SQL Server.

Enabling the Query Store: Query Store works at the database level on the server. Query Store is not active for new databases by default. You cannot enable the query store for the master or tempdb database. Available DMV sys.database_query_store_options (Transact-SQL) Collect Information in the Query Store: We collect all the available information from the three stores using Query Store DMV (Data Management Views). Query Plan Store: Persisting the execution plan information and it is accountable for capturing all information that is related to query compilation. sys.query_store_query (Transact-SQL) sys.query_store_plan (Transact-SQL) sys.query_store_query_text (Transact-SQL) Runtime Stats Store: Persisting the execution statistics information and it is probably the most frequently updated store. These statistics represent query execution data. sys.query_store_runtime_stats (Transact-SQL) Query Wait Stats Store: Persisting and capturing wait statistics information. sys.query_store_wait_stats (Transact-SQL)

注意:查询等待统计数据存储仅在SQL Server 2017+中可用


除了前面所说的,还有一件重要的事情需要知道。

Query plans are often too complex to be represented by the built-in XML column type which has a limitation of 127 levels of nested elements. That is one of the reasons why sys.dm_exec_query_plan may return NULL or even throw an error in earlier MS SQL versions, so generally it's safer to use sys.dm_exec_text_query_plan instead. The latter also has a useful bonus feature of selecting a plan for a particular statement rather than the whole batch. Here's how you use it to view plans for currently running statements:

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。 在Output窗格中,单击Plan。 默认情况下,您将看到查询的树表示形式。去看 查询计划时,单击“显示可视化”图标,或按 Ctrl + Shift + Alt + U


解释执行计划可能会非常详细,并占用大量阅读时间,但总的来说,如果你在查询之前使用'explain',它应该会给你很多信息,包括哪些部分首先执行等等。 如果你想了解更多关于这方面的细节,我写了一篇关于这方面的小博客,它也会给你指明正确的裁判。 https://medium.com/swlh/jetbrains-datagrip-explain-plan-ac406772c470


预估执行计划

估计的执行计划是由Optimizer在不运行SQL查询的情况下生成的。

为了获得估计的执行计划,您需要在执行查询之前启用SHOWPLAN_ALL设置。

SET SHOWPLAN_ALL ON

现在,当执行以下SQL查询时:

SELECT p.id
FROM post p
WHERE EXISTS (
  SELECT 1
  FROM post_comment pc
  WHERE
    pc.post_id = p.id AND
    pc.review = 'Bingo'
)
ORDER BY p.title
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY

SQL Server将生成以下估计的执行计划:

| NodeId | Parent | LogicalOp            | EstimateRows | EstimateIO  | EstimateCPU | AvgRowSize | TotalSubtreeCost | EstimateExecutions |
|--------|--------|----------------------|--------------|-------------|-------------|------------|------------------|--------------------|
| 1      | 0      | NULL                 | 10           | NULL        | NULL        | NULL       | 0.03374284       | NULL               |
| 2      | 1      | Top                  | 10           | 0           | 3.00E-06    | 15         | 0.03374284       | 1                  |
| 4      | 2      | Distinct Sort        | 30           | 0.01126126  | 0.000504114 | 146        | 0.03373984       | 1                  |
| 5      | 4      | Inner Join           | 46.698       | 0           | 0.00017974  | 146        | 0.02197446       | 1                  |
| 6      | 5      | Clustered Index Scan | 43           | 0.004606482 | 0.0007543   | 31         | 0.005360782      | 1                  |
| 7      | 5      | Clustered Index Seek | 1            | 0.003125    | 0.0001581   | 146        | 0.0161733        | 43                 |

在运行我们想要获得估计执行计划的查询之后,您需要禁用SHOWPLAN_ALL,否则,当前数据库会话将只生成估计的执行计划,而不是执行提供的SQL查询。

SET SHOWPLAN_ALL OFF

SQL Server Management Studio估计计划

在SQL Server Management Studio应用程序中,您可以通过按CTRL+L快捷键轻松获得任何SQL查询的估计执行计划。

实际执行计划

实际的SQL执行计划由Optimizer在运行SQL查询时生成。如果数据库表统计信息是准确的,那么实际计划应该与估计的计划没有太大差异。

要获得SQL Server上的实际执行计划,需要启用STATISTICS IO, TIME, PROFILE设置,如下SQL命令所示:

SET STATISTICS IO, TIME, PROFILE ON

现在,当运行前面的查询时,SQL Server将生成以下执行计划:

| Rows | Executes | NodeId | Parent | LogicalOp            | EstimateRows | EstimateIO  | EstimateCPU | AvgRowSize | TotalSubtreeCost |
|------|----------|--------|--------|----------------------|--------------|-------------|-------------|------------|------------------|
| 10   | 1        | 1      | 0      | NULL                 | 10           | NULL        | NULL        | NULL       | 0.03338978       |
| 10   | 1        | 2      | 1      | Top                  | 1.00E+01     | 0           | 3.00E-06    | 15         | 0.03338978       |
| 30   | 1        | 4      | 2      | Distinct Sort        | 30           | 0.01126126  | 0.000478783 | 146        | 0.03338679       |
| 41   | 1        | 5      | 4      | Inner Join           | 44.362       | 0           | 0.00017138  | 146        | 0.02164674       |
| 41   | 1        | 6      | 5      | Clustered Index Scan | 41           | 0.004606482 | 0.0007521   | 31         | 0.005358581      |
| 41   | 41       | 7      | 5      | Clustered Index Seek | 1            | 0.003125    | 0.0001581   | 146        | 0.0158571        |
 
SQL Server parse and compile time:
   CPU time = 8 ms, elapsed time = 8 ms.
 
(10 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'post'. Scan count 0, logical reads 116, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'post_comment'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 
(6 row(s) affected)
 
SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

运行查询后,我们感兴趣的是获得实际的执行计划,你需要禁用STATISTICS IO, TIME, PROFILE ON设置,如下所示:

SET STATISTICS IO, TIME, PROFILE OFF

SQL Server Management Studio实际计划

在SQL Server Management Studio应用程序中,您可以通过按CTRL+M快捷键轻松获得任何SQL查询的估计执行计划。


您也可以通过powershell使用SET STATISTICS XML ON来获得实际的计划。我写它是为了将多语句计划合并为一个计划;

    ########## BEGIN : SCRIPT VARIABLES #####################
    [string]$server = '.\MySQLServer'
    [string]$database = 'MyDatabase'
    [string]$sqlCommand = 'EXEC sp_ExampleSproc'
    [string]$XMLOutputFileName = 'sp_ExampleSproc'
    [string]$XMLOutputPath = 'C:\SQLDumps\ActualPlans\'
    ########## END   : SCRIPT VARIABLES #####################

    #Set up connection
    $connectionString = "Persist Security Info=False;Integrated Security=true;Connection Timeout=0;Initial Catalog=$database;Server=$server"
    $connection = new-object system.data.SqlClient.SQLConnection($connectionString)

    #Set up commands
    $command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
    $command.CommandTimeout = 0
    $commandXMLActPlanOn = new-object system.data.sqlclient.sqlcommand("SET STATISTICS XML ON",$connection)
    $commandXMLActPlanOff = new-object system.data.sqlclient.sqlcommand("SET STATISTICS XML OFF",$connection)

    $connection.Open()

    #Enable session XML plan
    $result = $commandXMLActPlanOn.ExecuteNonQuery()

    #Execute SP and return resultsets into a dataset
    $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
    $dataset = New-Object System.Data.DataSet
    $adapter.Fill($dataSet) | Out-Null

    #Set up output file name and path
    [string]$fileNameDateStamp = get-date -f yyyyMMdd_HHmmss
    [string]$XMLOutputFilePath = "$XMLOutputPath$XMLOutputFileName`_$fileNameDateStamp.sqlplan"

    #Pull XML plans out of dataset and merge into one multi-statement plan
    [int]$cntr = 1
    ForEach($table in $dataset.Tables)
    {
            if($table.Columns[0].ColumnName -eq "Microsoft SQL Server 2005 XML Showplan")
            {

                [string]$fullXMLPlan = $Table.rows[0]."Microsoft SQL Server 2005 XML Showplan"

                if($cntr -eq 1)
                    {

                    [regex]$rx = "\<ShowPlanXML xmlns\=.{1,}\<Statements\>"
                    [string]$startXMLPlan = $rx.Match($fullXMLPlan).Value
                    [regex]$rx = "\<\/Statements\>.{1,}\<\/ShowPlanXML\>"
                    [string]$endXMLPlan = $rx.Match($fullXMLPlan).Value

                    $startXMLPlan | out-file -Append -FilePath $XMLOutputFilePath

                    }

                [regex]$rx = "\<StmtSimple.{1,}\<\/StmtSimple\>"
                [string]$bodyXMLPlan = $rx.Match($fullXMLPlan).Value

                $bodyXMLPlan | out-file -Append -FilePath $XMLOutputFilePath

                $cntr += 1
            } 
    }

    $endXMLPlan | out-file -Append -FilePath $XMLOutputFilePath

    #Disable session XML plan
    $result = $commandXMLActPlanOff.ExecuteNonQuery()

    $connection.Close()

在SQL Server Management Studio:

“Ctrl + M”将生成实际执行计划

“Ctrl + L”将生成估计执行计划

“Shift + Alt + S”为客户端统计

“Ctrl + Alt + P”用于SQL Server Profiler中的跟踪查询。