Execution plans for mere mortals

45
Execution Plans for Mere Mortals A beginners overview of execution plans and what to look for.

Transcript of Execution plans for mere mortals

Execution Plans for Mere Mortals

A beginners overview of execution plans and what to look for.

Who Am I?Mike Lawell

Mike LawellPrincipal Consultant

Twitter: @SQLDiver

Blog: SQLServerAssociates.com

LinkedIn: LinkedIn.com/in/MikeLawell

EXECUTION STEPS

On The InsideRelational Engine

Optimizer

Command Parser

Query Executor

SNI

User

Storage Engine

Buffer Manager

Access Methods

Transaction Manager

SQL OS

Buffer Pool

Borrowed from Bradley Ball’s “SQL Internals, Recovery Models, & Backups” presentation

Plan Cache

Data Cache

Data

Query ParsingRelation Engine

1. Is the query syntactically correct?

SELECT [Nmae], [Number] FROM [Production].[Product]Msg 207, Level 16, State 1, Line 3

Invalid column name 'Nmae'.

SELCT [Name], [Number] FROM [Production].[Product]Msg 156, Level 15, State 1, Line 3

Incorrect syntax near the keyword 'FROM'.

2. No Errors Output as Parse Tree to Algebrizer

Query Parsing

SELECT [Nmae], [Number] FROM [Production].[Product]

Msg 207, Level 16, State 1, Line 3Invalid column name 'Nmae'.

Query Parsing

SELECT [Name], [Number] FROM [Production].[Product]

Algebrizer

1. Resolve the Names of the objects (tables, columns, etc.)

2. Resolve the data types for the objects being accessed.

3. Finds aggregate operations (min, max, group by) and performs an operation called aggregate binding.

If the names of the objects, columns aren’t found an error is output and the process halts.

If it is successful the algebrizer outputs the query processor tree to the query optimizer. The query hash is generated and passed with the query processor tree.

Query Optimizer

1. The query optimizer checks the hash against the plan cache. If it exists use it and the optimization step is skipped and plan is passed to query execution.

2. The query optimizer uses the query processor tree and the statistics to determine an estimated execution plan.

3. The optimizer goes through a process of using different types of joins and indexes and assigns a cost to each step by CPU and I/O and determines a cost for each possible estimated plan it generates.

4. Once an acceptable estimated plan is found it is stored in the plan cache then sent to the query execution.

Query Execution

Storage Engine

1. The storage engine determines if a recompile was triggered causing a change in the estimated execution plan.

2. SQL Server determines based upon cost whether it exceeds the threshold for parallelism changing the estimated plan for parallelism.

3. Statistics that have changed causing a change in the estimated plan.

SQL Server returns the results.

Cardinality EstimationThe optimization process depends on a cost estimation of each physical operator and the estimated number of records (cardinality estimation) to be processed.

DBCC SHOW_STATISTICS ("[Sales].[SalesOrderDetailEnlarged]", [_WA_Sys_00000003_3D7E1B63]);

The accuracy of the cardinality estimation depends upon the distribution of values in one or more columns of a table (statistics).Name Updated Rows Rows Sampled Steps Average key length String Index Filter Expression Unfiltered Rows_WA_Sys_00000003_3D7E1B63 Nov 26 2014 11:26AM 1000 1000 196 24 YES NULL 1000

RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS002EE045-E30 0 1 0 10169388E-8EC 6 1 6 1031622B3-B68 3 1 3 10424F840-4C2 3 1 3 104C4FEAC-7C1 3 1 3 1

Swag Question

Name_WA_Sys_00000003_3D7E1B63

Cardinality EstimationThere are multiple factors that can negatively impact the cardinality estimation process:

1. Out of date Statistics

SELECT object_name(object_id) as TableName, name AS stats_name,

STATS_DATE(object_id, stats_id) AS statistics_update_date

FROM sys.stats

WHERE object_id = OBJECT_ID('[Sales].[SalesOrderDetailEnlarged]');

2. Cardinality Estimation Errors

https://www.sqlskills.com/blogs/joe/cardinality-estimation-model-version/

Swag Question

Why 70 vs 120?

EXECUTION PLAN BASICS

Required Permissions

Server or database roles with permissions:sysadmin, dbcreator or db_owner or showplan

To give showplan rights to the database:GRANT SHOWPLAN TO [username];

How to Read

BASIC OPERATORS

Basic Operators

JOIN OPERATORS

Nested LoopNon-blocking

DescriptionFor each row in the top (outer) input, scan the bottom (inner) input, and output matching rows.

Where does it happen: Joins with indexes on join columns.

Nested Loop

SELECT [sod].[CarrierTrackingNumber], [sod].[OrderQty], [soh].[RevisionNumber], [soh].[OrderDateFROM [Sales].[SalesOrderHeader] sohJOIN [Sales].[SalesOrderDetail] sodON sod.[SalesOrderID] = soh.[SalesOrderID]WHERE soh.[OrderDate] = '2013-08-30 00:00:00.000'

Non-blocking

Outer

Inner

Nested LoopSalesOrderID RevisionNumber OrderDate55233 8 2013-08-30 00:00:00.00055234 8 2013-08-30 00:00:00.00055235 8 2013-08-30 00:00:00.00055236 8 2013-08-30 00:00:00.00055237 8 2013-08-30 00:00:00.00055238 8 2013-08-30 00:00:00.00055239 8 2013-08-30 00:00:00.00055240 8 2013-08-30 00:00:00.00055241 8 2013-08-30 00:00:00.00055242 8 2013-08-30 00:00:00.00055243 8 2013-08-30 00:00:00.00055244 8 2013-08-30 00:00:00.00055245 8 2013-08-30 00:00:00.00055246 8 2013-08-30 00:00:00.00055247 8 2013-08-30 00:00:00.00055248 8 2013-08-30 00:00:00.00055249 8 2013-08-30 00:00:00.00055250 8 2013-08-30 00:00:00.00055251 8 2013-08-30 00:00:00.00055252 8 2013-08-30 00:00:00.00055253 8 2013-08-30 00:00:00.000

SalesOrderID ProductID CarrierTrackingNumber OrderQty55233 738 1590-499E-95 555233 792 1590-499E-95 555233 793 1590-499E-95 455233 794 1590-499E-95 455233 795 1590-499E-95 455233 796 1590-499E-95 555233 797 1590-499E-95 655233 798 1590-499E-95 255233 799 1590-499E-95 155233 800 1590-499E-95 155233 801 1590-499E-95 655233 835 1590-499E-95 655233 874 1590-499E-95 855233 875 1590-499E-95 855233 938 1590-499E-95 555233 939 1590-499E-95 555233 940 1590-499E-95 455233 973 1590-499E-95 555233 974 1590-499E-95 155233 975 1590-499E-95 1

Non-blocking

DescriptionMatch rows from two suitably sorted input tables exploiting their sort order.

Where does it happen: Joins with indexes on join columns sorted in an appropriate sort order.

MergeNon-blocking

MergeNon-blocking

SELECT [sod].[CarrierTrackingNumber], [sod].[OrderQty], [soh].[RevisionNumber], [soh].[OrderDate]FROM [Sales].[SalesOrderHeader] sohJOIN [Sales].[SalesOrderDetail] sodON sod.[SalesOrderID] = soh.[SalesOrderID]

MergeNon-blocking

SalesOrderID RevisionNumber OrderDate55233 8 2013-08-30 00:00:00.00055234 8 2013-08-30 00:00:00.00055235 8 2013-08-30 00:00:00.00055236 8 2013-08-30 00:00:00.00055237 8 2013-08-30 00:00:00.00055238 8 2013-08-30 00:00:00.00055239 8 2013-08-30 00:00:00.00055240 8 2013-08-30 00:00:00.00055241 8 2013-08-30 00:00:00.00055242 8 2013-08-30 00:00:00.00055243 8 2013-08-30 00:00:00.00055244 8 2013-08-30 00:00:00.00055245 8 2013-08-30 00:00:00.00055246 8 2013-08-30 00:00:00.00055247 8 2013-08-30 00:00:00.00055248 8 2013-08-30 00:00:00.00055249 8 2013-08-30 00:00:00.00055250 8 2013-08-30 00:00:00.00055251 8 2013-08-30 00:00:00.00055252 8 2013-08-30 00:00:00.00055253 8 2013-08-30 00:00:00.000

SalesOrderID ProductID CarrierTrackingNumber OrderQty55233 738 1590-499E-95 555233 792 1590-499E-95 555233 793 1590-499E-95 455233 794 1590-499E-95 455233 795 1590-499E-95 455233 796 1590-499E-95 555233 797 1590-499E-95 655233 798 1590-499E-95 255233 799 1590-499E-95 155233 800 1590-499E-95 155233 801 1590-499E-95 655233 835 1590-499E-95 655233 874 1590-499E-95 855233 875 1590-499E-95 855233 938 1590-499E-95 555233 939 1590-499E-95 555233 940 1590-499E-95 455233 973 1590-499E-95 555233 974 1590-499E-95 155233 975 1590-499E-95 1

Hash Match

DescriptionUse each row from the top input to build a hash table, and each row from the bottom input to probe into the hash table, outputting all matching rows.

Where does it happen: Missing Index, Missing Where Clause, Where Clause that is non-sargable.

Hash MatchBlocking

SELECT [sod1].[ProductID], [sod1].[CarrierTrackingNumber], [sod1].[UnitPrice], [sod1].[OrderQty]FROM [Sales].[SalesOrderDetail] sod1JOIN [Sales].[SalesOrderDetail] sod2ON [sod1].[ProductID] = [sod2].[ProductID]AND [sod1].[CarrierTrackingNumber] = [sod2].[CarrierTrackingNumber]AND [sod1].[OrderQty] > 5

Hash MatchBlocking

ProductID CarrierTrackingNumber Hash707 4BC2-4C6D-83 -767544381711 2AA4-4D12-9F -767515863715 C811-4D40-80 -767499885715 8FCD-4D55-8F -767496256714 CC2F-4D47-8C -767488607712 BE3B-4D30-A7 -767488106707 9EBF-4C7E-82 -767471833716 F78B-4D68-8E -767470049712 8EBE-4D2C-AB -767459569716 7DE5-4D74-A7 -767455808715 46EF-4D44-A9 -767449380711 9FC2-4D08-A7 -767447057725 6B7D-4E47-B5 -767446438

ProductID CarrierTrackingNumber736 2554-4F68-AB -767556491717 9526-4D73-83 -767556433715 CC2F-4D47-8C -767554143715 2960-4D59-96 -767553412722 9708-4E22-A4 -767551834722 6F5C-4E3C-B5 -767549829717 7E0A-4D6E-9E -767545458707 4BC2-4C6D-83 -767544381716 F108-4D76-8A -767543168711 B900-4D0D-AF -767541067711 67A0-4D10-87 -767539667707 8441-4C6F-89 -767535798739 688B-4F92-AD -767532740

Hash Table 1 Hash Table 2

Fixed Hash Match

OTHER OPERATORS

Parallelism

SELECT [sod1].[ProductID], [sod1].[CarrierTrackingNumber], [sod1].[UnitPrice], [sod1].[OrderQty]FROM [Sales].[SalesOrderDetail] sod1JOIN [Sales].[SalesOrderDetail] sod2ON [sod1].[ProductID] = [sod2].[ProductID]AND [sod1].[CarrierTrackingNumber] = [sod2].[CarrierTrackingNumber]

ParallelismSET STATISTICS IO ONSET STATISTICS TIME ON

SELECT [sod1].[ProductID], [sod1].[CarrierTrackingNumber], [sod1].[UnitPrice], [sod1].[OrderQty]FROM [Sales].[SalesOrderDetail] sod1JOIN [Sales].[SalesOrderDetail] sod2ON [sod1].[ProductID] = [sod2].[ProductID]AND [sod1].[CarrierTrackingNumber] = [sod2].[CarrierTrackingNumber]

SELECT [sod1].[ProductID], [sod1].[CarrierTrackingNumber], [sod1].[UnitPrice], [sod1].[OrderQty]FROM [Sales].[SalesOrderDetail] sod1JOIN [Sales].[SalesOrderDetail] sod2ON [sod1].[ProductID] = [sod2].[ProductID]AND [sod1].[CarrierTrackingNumber] = [sod2].[CarrierTrackingNumber]OPTION(MAXDOP 1)

ParallelismTable 'SalesOrderDetail'. Scan count 18, logical reads 2490, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.Table 'Workfile'. 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 '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.

SQL Server Execution Times:CPU time = 9593 ms, elapsed time = 2381 ms.

Table 'Workfile'. 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 '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 'SalesOrderDetail'. Scan count 2, logical reads 2490, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:CPU time = 7941 ms, elapsed time = 8372 ms.

Parallelism

Hash AggregateSELECT [sod1].[CarrierTrackingNumber], sum([sod1].[UnitPrice]) UnitPriceTotal,

sum([sod1].[OrderQty]) as OrderQtyTotalFROM [Sales].[SalesOrderDetail] sod1JOIN [Sales].[SalesOrderDetail] sod2ON [sod1].[ProductID] = [sod2].[ProductID]AND [sod1].[CarrierTrackingNumber] = [sod2].[CarrierTrackingNumber]AND [sod1].[OrderQty] > 5GROUP BY [sod1].[CarrierTrackingNumber]

Stream AggregateSELECT [sod1].[CarrierTrackingNumber], sum([sod1].[UnitPrice]) UnitPriceTotal,

sum([sod1].[OrderQty]) as OrderQtyTotalFROM [Sales].[SalesOrderDetail] sod1JOIN [Sales].[SalesOrderDetail] sod2ON [sod1].[ProductID] = [sod2].[ProductID]AND [sod1].[CarrierTrackingNumber] = [sod2].[CarrierTrackingNumber]AND [sod1].[OrderQty] > 5GROUP BY [sod1].[CarrierTrackingNumber]

Sort (spill)

Operator used tempdb to spill data during execution with spill level 1

SELECT [sod].[CarrierTrackingNumber], [sod].[OrderQty], [soh].[RevisionNumber], [soh].[OrderDate]FROM [Sales].[SalesOrderHeader] sohJOIN [Sales].[SalesOrderDetailEnlarged] sodON sod.[SalesOrderID] = soh.[SalesOrderID]WHERE [sod].[CarrierTrackingNumber] > '41D0-42A8-A5'ORDER BY [soh].[RevisionNumber], [soh].[OrderDate]

Sort SpillSELECT TOP 1 [sod].[CarrierTrackingNumber], [sod].[OrderQty], [soh].[RevisionNumber], [soh].[OrderDate]FROM [Sales].[SalesOrderHeader] sohJOIN [Sales].[SalesOrderDetailEnlarged] sodON sod.[SalesOrderID] = soh.[SalesOrderID]WHERE [sod].[CarrierTrackingNumber] > '41D0-42A8-A5'ORDER BY [soh].[RevisionNumber], [soh].[OrderDate]

Implicit ConversionSELECT [sod].[ProductID], [sod].[CarrierTrackingNumber], [sod].[UnitPrice], [sod].[OrderQty], [rowguid]FROM [Sales].[SalesOrderDetail] sodWHERE LEFT([sod].[rowguid],4) = N'FE10'

Properties

Resources

http://www.red-gate.com/community/books/

DownloadableFREE!

Thank You!Mike LawellPrincipal Consultant

Twitter: @SQLDiver

Blog: SQLServerAssociates.com

LinkedIn: LinkedIn.com/in/MikeLawell

Email: [email protected]

Who Am I?Mike Lawell

Mike LawellPrincipal Consultant

Twitter: @SQLDiver

Blog: SQLServerAssociates.com

LinkedIn: LinkedIn.com/in/MikeLawell