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

发布于 2024-12-03 20:54:27 字数 51 浏览 3 评论 0 原文

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

In Microsoft SQL Server how can I get a query execution plan for a query / stored procedure?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

小兔几 2024-12-10 20:54:28

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

  1. SQL Server 现有组件通过利用查询存储管理器与查询存储进行交互。
  2. 查询存储管理器确定应使用哪个存储,然后将执行传递给该存储(计划或运行时统计信息或查询等待统计信息)
    • 计划存储 - 保留执行计划信息
    • 运行时统计信息存储 - 保存执行统计信息
    • 查询等待统计信息存储 - 保留等待统计信息。
  3. 计划、运行时统计和等待存储使用查询存储作为 SQL Server 的扩展。

输入图像描述这里

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

    • 默认情况下,查询存储对于新数据库不处于活动状态。
    • 您无法为 master 或 tempdb 数据库启用查询存储。
    • 可用的DMV

      <块引用>

      sys.database_query_store_options (Transact-SQL)

  2. 在查询存储中收集信息:我们从三个存储中收集所有可用信息使用查询存储 DMV(数据管理视图)。

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

Starting from SQL Server 2016+, Query Store feature was introduced to monitor performance. It provides insight into query plan choice and performance.
It’s not a complete replacement of trace or extended events, but as it’s evolving from version to version, we might get a fully functional query store in future releases from SQL Server.
The primary flow of Query Store

  1. SQL Server existing components interact with query store by utilising Query Store Manager.
  2. 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.
  3. Plan, Runtime Stats and Wait store uses Query Store as an extension to SQL Server.

enter image description here

  1. 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)

  2. Collect Information in the Query Store: We collect all the available information from the three stores using Query Store DMV (Data Management Views).

NOTE: Query Wait Stats Store is available only in SQL Server 2017+

爺獨霸怡葒院 2024-12-10 20:54:28

估计执行计划

估计执行计划是由优化器在不运行 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 估计计划

实际执行计划

实际的 SQL 执行计划是优化器在运行 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实际计划

Estimated execution plan

The estimated execution plan is generated by the Optimizer without running the SQL query.

In order to get the estimated execution plan, you need to enable the SHOWPLAN_ALL setting prior to executing the query.

SET SHOWPLAN_ALL ON

Now, when executing the following SQL query:

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 will generate the following estimated execution plan:

| 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                 |

After running the query we are interested in getting the estimated execution plan, you need to disable the SHOWPLAN_ALL as, otherwise, the current database session will only generate estimated execution plan instead of executing the provided SQL queries.

SET SHOWPLAN_ALL OFF

SQL Server Management Studio estimated plan

In the SQL Server Management Studio application, you can easily get the estimated execution plan for any SQL query by hitting the CTRL+L key shortcut.

SQL Server Management Studio estimated plan

Actual execution plan

The actual SQL execution plan is generated by the Optimizer when running the SQL query. If the database table statistics are accurate, the actual plan should not differ significantly from the estimated one.

To get the actual execution plan on SQL Server, you need to enable the STATISTICS IO, TIME, PROFILE settings, as illustrated by the following SQL command:

SET STATISTICS IO, TIME, PROFILE ON

Now, when running the previous query, SQL Server is going to generate the following execution plan:

| 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.

After running the query we are interested in getting the actual execution plan, you need to disable the STATISTICS IO, TIME, PROFILE ON settings like this:

SET STATISTICS IO, TIME, PROFILE OFF

SQL Server Management Studio actual plan

In the SQL Server Management Studio application, you can easily get the estimated execution plan for any SQL query by hitting the CTRL+M key shortcut.

SQL Server Management Studio actual plan

流云如水 2024-12-10 20:54:28

可以通过 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:实时数据”选项卡中看到一些结果。单击网格中的 query_post_execution_showplan 事件之一,然后单击网格下方的“查询计划”选项卡。它应该类似于:

在此处输入图像描述

编辑:XEvent 代码和屏幕截图是从 SQL/SSMS 2012 w/ SP2 生成的。如果您使用的是 SQL 2008/R2,您可能可以调整脚本以使其运行。但该版本没有 GUI,因此您必须提取显示计划 XML,将其另存为 *.sqlplan 文件并在 SSMS 中打开它。那很麻烦。 XEvents 在 SQL 2005 或更早版本中不存在。因此,如果您没有使用 SQL 2012 或更高版本,我强烈建议您使用此处发布的其他答案之一。

Query plans can be obtained from an Extended Events session via the query_post_execution_showplan event. Here's a sample XEvent session:

/*
    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

After you create the session, (in SSMS) go to the Object Explorer and delve down into Management | Extended Events | Sessions. Right-click the "GetExecutionPlan" session and start it. Right-click it again and select "Watch Live Data".

Next, open a new query window and run one or more queries. Here's one for 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

After a moment or two, you should see some results in the "GetExecutionPlan: Live Data" tab. Click one of the query_post_execution_showplan events in the grid, and then click the "Query Plan" tab below the grid. It should look similar to this:

enter image description here

EDIT: The XEvent code and the screen shot were generated from SQL/SSMS 2012 w/ SP2. If you're using SQL 2008/R2, you might be able to tweak the script to make it run. But that version doesn't have a GUI, so you'd have to extract the showplan XML, save it as a *.sqlplan file and open it in SSMS. That's cumbersome. XEvents didn't exist in SQL 2005 or earlier. So, if you're not on SQL 2012 or later, I'd strongly suggest one of the other answers posted here.

那小子欠揍 2024-12-10 20:54:28

除了前面所说的一切之外,还有一件重要的事情需要了解。

查询计划通常过于复杂,无法用内置 XML 列类型来表示,该类型的嵌套元素限制为 127 层。这就是sys.dm_exec_query_plan 可能会返回 NULL 甚至在早期的 MS SQL 版本中抛出错误,因此通常使用 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

Here's one important thing to know in addition to everything said before.

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

The text column in the resulting table is however not very handy compared to an XML column. To be able to click on the result to be opened in a separate tab as a diagram, without having to save its contents to a file, you can use a little trick (remember you cannot just use CAST(... AS XML)), although this will only work for a single row:

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
我很OK 2024-12-10 20:54:28

与 SQL Server Management Studio 一样(已经解释过),也可以使用 Datagrip,如下所述 此处

  1. 右键单击 SQL 语句,然后选择“解释计划”。
  2. 在“输出”窗格中,点击“计划”。
  3. 默认情况下,您会看到查询的树表示形式。为了看到
    查询计划,单击显示可视化图标,或按
    Ctrl+Shift+Alt+U

Like with SQL Server Management Studio (already explained), it is also possible with Datagrip as explained here.

  1. Right-click an SQL statement, and select Explain plan.
  2. In the Output pane, click Plan.
  3. By default, you see the tree representation of the query. To see the
    query plan, click the Show Visualization icon, or press
    Ctrl+Shift+Alt+U
孤独难免 2024-12-10 20:54:28

您还可以通过 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()

You can also do it via powershell using SET STATISTICS XML ON to get the actual plan. I've written it so that it merges multi-statement plans into one plan;

    ########## 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()
画尸师 2024-12-10 20:54:28

解释执行计划可能非常详细,并且会占用相当多的阅读时间,但总而言之,如果您在查询之前使用“解释”,它应该为您提供大量信息,包括首先执行哪些部分等。
如果您想了解更多有关此内容的详细信息,我编写了一个有关此内容的小博客,它也为您指出了正确的参考文献。
https://medium.com/swlh/jetbrains-datagrip-explain-plan- ac406772c470

Explaining execution plan can be very detailed and takes up quite a reading time, but in summary if you use 'explain' before the query it should give you a lot of info including which parts were executed first and so.
if you wanna read a bit more details about this, I compiled a small blog about this which points you as well to the right refs.
https://medium.com/swlh/jetbrains-datagrip-explain-plan-ac406772c470

攀登最高峰 2024-12-10 20:54:28

在 SQL Server Management Studio 中:

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

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

“Shift + Alt + S”用于客户端统计

“Ctrl + Alt + P”用于在 SQL 中跟踪查询服务器分析器。

In SQL Server Management Studio:

“Ctrl + M” will generate the Actual Execution Plan

“Ctrl + L” will generate the Estimated Execution Plan

"Shift + Alt + S" for Client Statistics

"Ctrl + Alt + P" for tracing query in SQL Server Profiler.

暮年 2024-12-10 20:54:27

获取执行计划的方法有很多种,使用哪一种取决于您的具体情况。通常您可以使用 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 - 显示基于基本文本的估计执行计划,而不执行查询
  • SHOWPLAN_ALL - 显示基于文本的估计执行计划以及成本估计,而不执行查询
  • SHOWPLAN_XML - 显示基于 XML 的估计执行计划以及成本估计,而不执行查询。这相当于 SQL Server Management Studio 中的“显示估计执行计划...”选项。
  • STATISTICS PROFILE - 执行查询并显示基于文本的实际执行计划。
  • STATISTICS XML - 执行查询并显示基于 XML 的实际执行计划。这相当于 SQL Server Management Studio 中的“包括实际执行计划”选项。

方法 3 - 使用 SQL Server Profiler

如果您无法直接运行查询(或者直接执行时查询运行速度并不慢 - 请记住我们想要一个执行得很差的查询计划),那么您可以使用以下命令捕获计划SQL Server Profiler 跟踪。这个想法是在捕获“Showplan”事件之一的跟踪正在运行时运行查询。

请注意,根据负载,您可以在生产环境中使用此方法,但显然应该谨慎使用。 SQL Server 分析机制旨在最大限度地减少对数据库的影响,但这并不意味着不会对性能产生任何影响。如果您的数据库被大量使用,您也可能会在过滤和识别跟踪中的正确计划时遇到问题。显然,您应该咨询您的 DBA,看看他们是否满意您在他们宝贵的数据库上执行此操作!

  1. 打开 SQL Server Profiler 并创建一个新的跟踪,连接到您希望记录跟踪的所需数据库。
  2. 在“事件选择”选项卡下选中“显示所有事件”,选中“性能”-> “Showplan XML”行并运行跟踪。
  3. 当跟踪运行时,执行您需要执行的任何操作以使运行缓慢的查询运行。
  4. 等待查询完成并停止跟踪。
  5. 要保存跟踪,请右键单击 SQL Server Profiler 中的计划 xml,然后选择“提取事件数据...”以将计划保存为 XML 格式的文件。

您获得的计划相当于 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 以在新窗口中打开计划 - 右键单击​​并选择“将执行计划另存为...”以将计划保存为 XML 格式的文件。

注意:

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

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

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

实际执行计划是 SQL Server 实际运行查询的计划,而估计执行计划是 SQL Server 计算出的结果 >会不执行查询。虽然逻辑上等效,但实际执行计划更有用,因为它包含有关执行查询时实际发生的情况的附加详细信息和统计信息。当诊断 SQL Server 估计不准确的问题时(例如当统计信息过时时),这一点至关重要。

如何解释查询执行计划?

这是一个足够值得(免费)本身。

另请参阅:

There are a number of methods of obtaining an execution plan, which one to use will depend on your circumstances. Usually you can use SQL Server Management Studio to get a plan, however if for some reason you can't run your query in SQL Server Management Studio then you might find it helpful to be able to obtain a plan via SQL Server Profiler or by inspecting the plan cache.

Method 1 - Using SQL Server Management Studio

SQL Server comes with a couple of neat features that make it very easy to capture an execution plan, simply make sure that the "Include Actual Execution Plan" menu item (found under the "Query" menu) is ticked and run your query as normal.

Include Action Execution Plan menu item

If you are trying to obtain the execution plan for statements in a stored procedure then you should execute the stored procedure, like so:

exec p_Example 42

When your query completes you should see an extra tab entitled "Execution plan" appear in the results pane. If you ran many statements then you may see many plans displayed in this tab.

Screenshot of an Execution Plan

From here you can inspect the execution plan in SQL Server Management Studio, or right click on the plan and select "Save Execution Plan As ..." to save the plan to a file in XML format.

Method 2 - Using SHOWPLAN options

This method is very similar to method 1 (in fact this is what SQL Server Management Studio does internally), however I have included it for completeness or if you don't have SQL Server Management Studio available.

Before you run your query, run one of the following statements. The statement must be the only statement in the batch, i.e. you cannot execute another statement at the same time:

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

These are connection options and so you only need to run this once per connection. From this point on all statements run will be acompanied by an additional resultset containing your execution plan in the desired format - simply run your query as you normally would to see the plan.

Once you are done you can turn this option off with the following statement:

SET <<option>> OFF

Comparison of execution plan formats

Unless you have a strong preference my recommendation is to use the STATISTICS XML option. This option is equivalent to the "Include Actual Execution Plan" option in SQL Server Management Studio and supplies the most information in the most convenient format.

  • 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.

Method 3 - Using SQL Server Profiler

If you can't run your query directly (or your query doesn't run slowly when you execute it directly - remember we want a plan of the query performing badly), then you can capture a plan using a SQL Server Profiler trace. The idea is to run your query while a trace that is capturing one of the "Showplan" events is running.

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!

  1. Open SQL Server Profiler and create a new trace connecting to the desired database against which you wish to record the trace.
  2. Under the "Events Selection" tab check "Show all events", check the "Performance" -> "Showplan XML" row and run the trace.
  3. While the trace is running, do whatever it is you need to do to get the slow running query to run.
  4. Wait for the query to complete and stop the trace.
  5. 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.

The plan you get is equivalent to the "Include Actual Execution Plan" option in SQL Server Management Studio.

Method 4 - Inspecting the query cache

If you can't run your query directly and you also can't capture a profiler trace then you can still obtain an estimated plan by inspecting the SQL query plan cache.

We inspect the plan cache by querying SQL Server DMVs. The following is a basic query which will list all cached query plans (as xml) along with their SQL text. On most database you will also need to add additional filtering clauses to filter the results down to just the plans you are interested in.

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)

Execute this query and click on the plan XML to open up the plan in a new window - right click and select "Save execution plan as..." to save the plan to file in XML format.

Notes:

Because there are so many factors involved (ranging from the table and index schema down to the data stored and the table statistics) you should always try to obtain an execution plan from the database you are interested in (normally the one that is experiencing a performance problem).

You can't capture an execution plan for encrypted stored procedures.

"actual" vs "estimated" execution plans

An actual execution plan is one where SQL Server actually runs the query, whereas an estimated execution plan SQL Server works out what it would do without executing the query. Although logically equivalent, an actual execution plan is much more useful as it contains additional details and statistics about what actually happened when executing the query. This is essential when diagnosing problems where SQL Servers estimations are off (such as when statistics are out of date).

How do I interpret a query execution plan?

This is a topic worthy enough for a (free) book in its own right.

See also:

蓝色星空 2024-12-10 20:54:27

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

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

In addition to the comprehensive answer already posted sometimes it is useful to be able to access the execution plan programatically to extract information. Example code for this is below.

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

Example StartCapture Definition

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

Example StopCapture Definition

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
拔了角的鹿 2024-12-10 20:54:27

假设您使用的是 Microsoft SQL Server Management Studio

  • 进行估计查询计划,您可以按 Ctrl + L 或以下按钮。

输入图像描述这里

  • 对于实际查询计划,您可以按Ctrl +
    在执行查询之前按 M
    或以下按钮。

输入图像描述这里

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

输入图像描述这里

Assuming you're using Microsoft SQL Server Management Studio

  • For Estimated Query Plan you can press Ctrl + L or the following button.

enter image description here

  • For Actual Query Plan, you can press Ctrl +
    M
    or the following button before executing query.

enter image description here

  • For Live Query Plan, (only in SSMS 2016) use the following button before executing query.

enter image description here

放手` 2024-12-10 20:54:27

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

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

在 ApexSQL Plan 中查看估计执行计划

  1. 单击 SSMS 中的新建查询按钮,并将查询文本粘贴到查询文本窗口中。右键单击并从上下文菜单中选择“显示估计执行计划”选项。

新建查询按钮在 SSMS

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

执行计划

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

预计执行计划

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

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

单击“主功能区栏上的“实际”按钮

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

实际执行计划

有关查看执行计划的更多信息,请参阅此链接

Beside the methods described in previous answers, you can also use a free execution plan viewer and query optimization tool ApexSQL Plan (which I’ve recently bumped into).

You can install and integrate ApexSQL Plan into SQL Server Management Studio, so execution plans can be viewed from SSMS directly.

Viewing Estimated execution plans in ApexSQL Plan

  1. Click the New Query button in SSMS and paste the query text in the query text window. Right click and select the “Display Estimated Execution Plan” option from the context menu.

New Query button in SSMS

  1. The execution plan diagrams will be shown the Execution Plan tab in the results section. Next right-click the execution plan and in the context menu select the “Open in ApexSQL Plan” option.

Execution Plan

  1. The Estimated execution plan will be opened in ApexSQL Plan and it can be analyzed for query optimization.

Estimated execution plan

Viewing Actual execution plans in ApexSQL Plan

To view the Actual execution plan of a query, continue from the 2nd step mentioned previously, but now, once the Estimated plan is shown, click the “Actual” button from the main ribbon bar in ApexSQL Plan.

click the “Actual” button from the main ribbon bar

Once the “Actual” button is clicked, the Actual execution plan will be shown with detailed preview of the cost parameters along with other execution plan data.

Actual execution plan

More information about viewing execution plans can be found by following this link.

风吹雨成花 2024-12-10 20:54:27

我最喜欢的用于获取和深入分析查询执行计划的工具是 SQL Sentry Plan Explorer< /a>.与SSMS相比,它对于执行计划的详细分析和可视化更加人性化、方便和全面。

下面是一个示例屏幕截图,可让您了解该工具提供的功能:

SQL Sentry Plan Explorer 窗口屏幕截图

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

此外,我没有注意到其免费版本有任何限制,这些限制会阻止您每天使用它或迫使您最终购买专业版。因此,如果您愿意坚持使用免费版本,没有什么可以禁止您这样做。

My favourite tool for obtaining and deeply analyzing query execution plans is SQL Sentry Plan Explorer. It's much more user-friendly, convenient and comprehensive for the detail analysis and visualization of execution plans than SSMS.

Here is a sample screen shot for you to have an idea of what functionality is offered by the tool:

SQL Sentry Plan Explorer window screen shot

It's only one of the views available in the tool. Notice a set of tabs to the bottom of the app window, which lets you get different types of your execution plan representation and useful additional information as well.

In addition, I haven't noticed any limitations of its free edition that prevents using it on a daily basis or forces you to purchase the Pro version eventually. So, if you prefer to stick with the free edition, nothing forbids you from doing so.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文