如何在SQL Server中获取查询执行计划?

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

478187 次浏览

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

方法1 -使用SQL Server Management Studio

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

包含行动执行计划菜单项

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

exec p_Example 42

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

截图of an Execution Plan

从这里,您可以在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 -显示一个基于估计执行计划的基本文本,不执行查询
  • 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”事件之一的跟踪运行时运行查询。

请注意,在生产环境中使用此方法取决于您可以的负载,但显然应该谨慎使用。SQL Server剖析机制被设计成最小化对数据库的影响,但这并不意味着不会有任何性能影响。如果数据库被大量使用,您还可能在跟踪中筛选和识别正确的计划时遇到问题。显然,您应该与您的DBA联系,看看他们是否乐意您在他们宝贵的数据库上执行此操作!

  1. 打开SQL Server Profiler并创建一个新的跟踪,连接到您希望记录跟踪的所需数据库。
  2. 在“Events Selection”页签下,检查“Show all Events”,检查“Performance”->“Showplan XML”行,并运行跟踪。
  3. 在跟踪运行时,执行您需要执行的任何操作,以使运行缓慢的查询运行起来。
  4. 等待查询完成并停止跟踪。
  5. 要保存跟踪,右键单击SQL Server Profiler中的计划xml,并选择“Extract event data…”以xml格式将计划保存到文件中。

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

方法4 -检查查询缓存

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

我们通过查询SQL Server 汽车登记处来检查计划缓存。下面是一个基本查询,它将列出所有缓存的查询计划(以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估计错误的问题(例如统计数据过期)时非常重要。

如何解释查询执行计划?

这是一个值得(免费)单独讨论的话题。

参见:

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

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

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

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

SQL哨兵计划资源管理器窗口截图

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

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

查询计划可以通过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”选项卡。它应该看起来像这样:

enter image description here

编辑: 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或下面的按钮。

enter image description here

    对于实际查询计划,可以按Ctrl + M或执行查询前的以下按钮

enter image description here

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

enter image description here

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

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

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

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

 SSMS中的新查询按钮

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

Execution Plan

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

估计执行计划

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

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

点击

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

实际执行计划

有关查看执行计划的更多信息可以通过这个链接找到。

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

的主要流
  1. SQL Server现有组件通过使用查询存储管理器与查询存储进行交互。
  2. 查询存储管理器确定应该使用哪个存储,然后将执行传递给该存储(计划或运行时统计或查询等待统计)
    • 计划存储—持久化执行计划信息
    • 运行时统计存储——持久化执行统计信息
    • 查询等待统计信息存储—持久化等待统计信息。
    • 李< / ul > < / >
    • 计划、运行时统计和等待存储使用查询存储作为SQL Server的扩展。

enter image description here

  1. 启用查询存储:查询存储工作在服务器的数据库级别。

    • 默认情况下,对于新数据库,查询存储区不是活动的。
    • 不能为主数据库或tempdb数据库启用查询存储。
    • <李> DMV可用

      sys.database_query_store_options (transact - sql)

      李< /引用> < / > 李< / ul > < / >
    • 在查询存储中收集信息:我们使用查询存储DMV(数据管理视图)从三个存储收集所有可用的信息。

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

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

查询计划通常太复杂,不能用内置的XML列类型表示,它有127级限制的嵌套元素。这就是为什么在早期的MS SQL版本中sys.dm_exec_query_plan可能返回NULL甚至抛出错误的原因之一,所以通常使用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,如在这里所解释的那样。

  1. 右键单击SQL语句,并选择Explain plan。
  2. 在Output窗格中,单击Plan。
  3. 默认情况下,您将看到查询的树表示形式。去看 查询计划时,单击“显示可视化”图标,或按 李Ctrl + Shift + Alt + U < / >
解释执行计划可能会非常详细,并占用相当长的阅读时间,但总的来说,如果你在查询之前使用'explain',它应该会给你很多信息,包括哪些部分首先执行等等。 如果你想了解更多关于这方面的细节,我写了一篇关于这方面的小博客,它也会给你指明正确的裁判。 https://medium.com/swlh/jetbrains-datagrip-explain-plan-ac406772c470 < / p >

预估执行计划

估计的执行计划是由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 Server Management Studio estimated plan

实际执行计划

实际的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查询的估计执行计划。

SQL Server Management Studio实际计划

您也可以通过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中的跟踪查询。