Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 1013 Vote(s) - 3.56 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How do I obtain a Query Execution Plan in SQL Server?

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

#2
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
Reply

#3
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][1]][1]


[1]:


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

#4
> 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][1]][1]


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

[![enter image description here][2]][2]

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

[![enter image description here][3]][3]


[1]:

[2]:

[3]:
Reply

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

<h2>Method 1 - Using SQL Server Management Studio</h2>

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][2]

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][3]

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.

<h2>Method 2 - Using SHOWPLAN options</h2>

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

<h3>Comparison of execution plan formats</h3>

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.

<h2>Method 3 - Using SQL Server Profiler</h2>

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.

<h2>Method 4 - Inspecting the query cache</h2>

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][4]. 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.

<h1>Notes:</h1>

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.

<h2>"actual" vs "estimated" execution plans</h2>

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

- [Estimated and Actual execution plan revisited](

[To see links please register here]

)

<h2>How do I interpret a query execution plan?</h2>

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

<h2>See also:</h2>

- [Execution Plan Basics](

[To see links please register here]

)
- [SHOWPLAN Permission and Transact-SQL Batches](

[To see links please register here]

)
- [SQL Server 2008 – Using Query Hashes and Query Plan Hashes](

[To see links please register here]

)
- [Analyzing the SQL Server Plan Cache](

[To see links please register here]

)

[1]:

[To see links please register here]

[2]:

[3]:

[4]:

[To see links please register here]

[5]:

[To see links please register here]

Reply

#6
Beside the methods described in previous answers, you can also use a free execution plan viewer and query optimization tool [ApexSQL Plan](

[To see links please register here]

) (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]][1]


2. 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][2]][2]

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

[![Estimated execution plan][3]][3]

**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][4]][4]

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][5]][5]

More information about viewing execution plans can be found by following [this link](

[To see links please register here]

).


[1]:

[2]:

[3]:

[4]:

[5]:
Reply

#7
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]][1]


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`][2] (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).

- **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`][3] (Transact-SQL)
> [`sys.query_store_plan`][4] (Transact-SQL)
> [`sys.query_store_query_text`][5] (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`][6] (Transact-SQL)

- **Query Wait Stats Store:**
Persisting and capturing wait statistics information.
> [`sys.query_store_wait_stats`][7] (Transact-SQL)

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

[1]:

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

[5]:

[To see links please register here]

[6]:

[To see links please register here]

[7]:

[To see links please register here]

Reply

#8
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][1] 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][2] 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:

<!-- language: t-sql -->

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:

<!-- language: t-sql -->

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


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#9
Like with SQL Server Management Studio (already explained), it is also possible with Datagrip as explained [here][1].

> 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

[1]:

[To see links please register here]

Reply

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

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through