<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tag 'Trace Flags'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=Trace+Flags&amp;orTags=0</link><description>Search results matching tag 'Trace Flags'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Execution Plan Analysis: The Mystery Work Table</title><link>http://sqlblog.com/blogs/paul_white/archive/2013/03/07/execution-plan-analysis-the-mystery-work-table.aspx</link><pubDate>Thu, 07 Mar 2013 19:42:04 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:48117</guid><dc:creator>Paul White</dc:creator><description>&lt;p align="left"&gt;&lt;a title="SQL Intersection" href="http://www.sqlintersection.com/" target="_blank"&gt;&lt;img title="Ill_Be_There4" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;float:right;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Ill_Be_There4" align="right" src="http://sqlblog.com/blogs/paul_white/Ill_Be_There4_2CF1D80C.jpg" width="140" height="110" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;I love SQL Server execution plans. It is often &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;easy to spot the cause of a performance problem just by looking at one. The task is considerably easier if the plan includes run-time information (a so-called ‘actual’ execution plan), but even a compiled plan can be very useful. &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;Nevertheless, there are still times where the execution plan does not tell the whole story, and we need to think more deeply about query execution to really understand a performance problem. This post looks at one such example, based on a recent &lt;a href="https://answers.sqlperformance.com/questions/392/there-are-2-identical-worksets-in-question-this-is.html" target="_blank"&gt;question&lt;/a&gt; posted on the &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;SQL Performance Q &amp;amp; A site.&lt;/font&gt;&lt;/p&gt;  &lt;h2&gt;The Execution Plan&lt;/h2&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_116CD609.png" target="_blank"&gt;&lt;img title="Original Query Plan" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Original Query Plan" src="http://sqlblog.com/blogs/paul_white/image_thumb_23D526BE.png" width="660" height="212" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;This plan is reasonably large (20MB cached plan size) but not massively complex once you break it down (click on the image above to view it full-size in a new window). The context of the question is that this query usually executes in less than a minute, but sometimes it runs for nearly twenty minutes – though the plan appears identical.&lt;/font&gt;&lt;/p&gt;  &lt;h3&gt;High-Cost Operators&lt;/h3&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;There are many different things to look for in execution plans. What you choose to look at first is as much a matter of personal preference as anything, but many people &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;are drawn to &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;high-cost operators, so I will start there. In this plan, the cost of one operator dominates all others, shown as being responsible for &lt;strong&gt;100% of the cost of the query&lt;/strong&gt;. It is highlighted in red in Plan Explorer; I have expanded the relevant plan section (the top right) below:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_20738F16.png" target="_blank"&gt;&lt;img title="100% operator cost" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="100% operator cost" src="http://sqlblog.com/blogs/paul_white/image_thumb_10844A52.png" width="549" height="268" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="3" face="Calibri"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;There is no doubt that this seek is busy little thing. It is executed &lt;strong&gt;249,484 times&lt;/strong&gt;, though it only produces a grand total of 167,813 rows over all iterations of the loop join – an average of just 0.7 rows per seek. There are all sorts of interesting details in the plan about this seek – I could write a whole blog post about it – but &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;two details that stand out are the “&lt;em&gt;Force Seek: True&lt;/em&gt;” and “&lt;em&gt;Partitioned: True&lt;/em&gt;” attributes. &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;These tell us that the base table is partitioned, and the query writer had to use a FORCESEEK table hint to get this plan.&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;Without this hint, the optimizer would almost certainly choose &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;a Hash Match or Merge Join rather than Nested Loops. This is understandable given the optimizer’s cost model and the simplifying assumptions it makes (such as assuming every query starts with a cold buffer cache). &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;That’s fine, but we can see from the query plan that &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;the inner-side table has &lt;strong&gt;643 million rows&lt;/strong&gt;. Left to its own devices, the optimizer would estimate that it would be faster to perform a sequential scan of 643 million rows (with large-block read-ahead) than it would be to run a quarter-million randomly-distributed seeks driven by a Nested Loops join.&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;I doubt that the optimizer’s reasoning here is sound (at least on any reasonably modern hardware) but there we go. The query author probably knows that a good fraction of this table is likely to be in cache, so &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;with all that in mind, I think we can reasonably assume at this stage that the FORCESEEK hint is genuinely needed here, and this part of the plan is at least reasonably optimal.&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;Important note: The seek certainly does not account for 100% of the runtime cost of this query. &lt;strong&gt;Remember cost percentages are always estimates – even in ‘actual’ plans&lt;/strong&gt;. It can be useful to check the reasons for high-estimated-cost operators, but they should never be used as a primary tuning metric.&lt;/font&gt;&lt;/p&gt;  &lt;h3&gt;Execution Warnings&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_353561C9.png"&gt;&lt;img title="Sort Warning" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Sort Warning" src="http://sqlblog.com/blogs/paul_white/image_thumb_0597433D.png" width="310" height="173" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;This query was executed on SQL Server 2012, so there is a handy warning triangle on the Sort operator indicating that one or more sort runs had to be spilled to physical &lt;em&gt;tempdb&lt;/em&gt; disk. The plan clearly shows this spilling is a result of an inaccurate cardinality estimate at the Filter operator (the estimates are not bad at all prior to this). The Sort expects &lt;strong&gt;9,217 rows&lt;/strong&gt; totalling approximately 5MB, but actually encountered &lt;strong&gt;61,846 rows&lt;/strong&gt; in 35MB. As you may know, memory for sorts and hashes is allocated before execution starts, and generally cannot expand dynamically at run time.&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The spilled sort is undesirable, of course, but it is unlikely to be a major cause of the occasional poor performance given the small size of the spilled data. Nevertheless, this might be a good place to split this query up. The idea would be to write the results of the query (up to and including the Filter) to a temporary heap table using SELECT INTO, and then create a clustered index with the same keys as the Sort operator. The temporary table would not be large, and may well perform better overall than the spilled sort, including the cost of creating the clustered index. Of course, creating this index will involve a sort, but it will be one based on the known cardinality of the temporary heap table. The part of the plan that could be replaced by a temporary table is shown below:&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_31D3CA21.png"&gt;&lt;img title="Plan subtree replaced with a temp table" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Plan subtree replaced with a temp table" src="http://sqlblog.com/blogs/paul_white/image_thumb_40BAF93B.png" width="640" height="298" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;I am a big fan of simplifications like this. Smaller execution plans tend to optimize better for all sorts of reasons, and the source code usually becomes easier to maintain as well. I should mention t&lt;/font&gt;&lt;font size="3" face="Calibri"&gt;here is another warning triangle in the 2012 execution plan (shown on the root icon), which relates to some implicit conversions that I will mention later.&lt;/font&gt;&lt;/p&gt;  &lt;h3 align="left"&gt;I/O Information&lt;/h3&gt;  &lt;p&gt;&lt;font size="3" face="Calibri"&gt;The execution plan was captured with Plan Explorer, so we can also easily see I/O statistics for the two executions. The first is for a fast (sub-60-second) run:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_3C80FBA9.png"&gt;&lt;img title="I/O data - fast" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="I/O data - fast" src="http://sqlblog.com/blogs/paul_white/image_thumb_41833958.png" width="664" height="260" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;Overall, these I/O numbers show pretty much what we would expect: a decent number of logical reads associated with the seeks into the Trans table (but certainly not 100% of the total, ha ha), a very small number of physical reads, and a small amount of read-ahead activity on a couple of tables.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="3" face="Calibri"&gt;The second set of I/O data is from a slow run (18 minutes or so):&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_3846FE17.png"&gt;&lt;img title="I/O data - slow" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="I/O data - slow" src="http://sqlblog.com/blogs/paul_white/image_thumb_2F0AC2D6.png" width="650" height="278" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The very obvious difference is the appearance of a work table, with &lt;strong&gt;178 million logical reads &lt;/strong&gt;and &lt;strong&gt;130 million LOB logical reads&lt;/strong&gt;. It seems very likely this work table, and its &lt;strong&gt;300 million logical reads&lt;/strong&gt;, is responsible for the dramatic decrease in query performance. But given that the execution plans are identical (right down to the XML) what is causing this?&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;My answer to that question (on the Q &amp;amp; A site) was that it is related to the increased level of read-ahead activity, but to see why that is the case, we will need to reproduce the issue and dig a bit deeper.&lt;/font&gt;&lt;/p&gt;  &lt;h2 align="left"&gt;Execution Outline&lt;/h2&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;Before we really get going on this, it will be useful to take a look at what the execution plan is doing in outline. We saw the first part of the plan earlier when looking at the spilling sort. The data set at that point (which we would like to write to a temporary table, remember) essentially represents source data for a second query, which uses &lt;/font&gt;&lt;font size="3" face="Calibri"&gt;a series of Nested Loops Left Joins to lookup information from other tables:&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_68AD5CC0.png"&gt;&lt;img title="Nested Loop Lookups" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Nested Loop Lookups" src="http://sqlblog.com/blogs/paul_white/image_thumb_4A7F9F0C.png" width="659" height="98" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The inner side of each join involves some reasonably involved logic, which is thankfully not important to the present discussion. What is important is that the result of each lookup is a LOB data type. This begins to shed some light on the LOB logical reads reported against the work table, but it does not explain why the work table (and the 300 million associated reads) do not appear when the query runs quickly (with the same execution plan).&lt;/font&gt;&lt;/p&gt;  &lt;h2 align="left"&gt;Reproducing the problem&lt;/h2&gt;  &lt;h3 align="left"&gt;Table Creation&lt;/h3&gt;  &lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The first part of the repro involves creating six tables that represent the lookup tables in the original query plan. Each table will have 10,000 rows, consisting of a sequential reference number and a second column containing a 2048 single-byte-character string. &lt;font size="3" face="Calibri"&gt;The source table used to drive the lookups will be a regular Numbers table containing just a single integer column.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div id="codeSnippetWrapper" style="overflow:auto;cursor:text;font-size:8pt;border-top:silver 1px solid;font-family:'Courier New', courier, monospace;border-right:silver 1px solid;border-bottom:silver 1px solid;padding-bottom:4px;direction:ltr;text-align:left;padding-top:4px;padding-left:4px;margin:20px 0px 10px;border-left:silver 1px solid;line-height:12pt;padding-right:4px;max-height:200px;width:97.5%;background-color:#f4f4f4;"&gt;   &lt;div id="codeSnippet" style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;     &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T1 (id &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;, d &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(2048));&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T2 (id &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;, d &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(2048));&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T3 (id &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;, d &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(2048));&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T4 (id &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;, d &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(2048));&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T5 (id &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;, d &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(2048));&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T6 (id &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;, d &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(2048));&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;INSERT dbo.T1 &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (TABLOCKX)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; REPLICATE(&lt;span style="color:#006080;"&gt;'A'&lt;/span&gt;, 2048)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;INSERT dbo.T2 &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (TABLOCKX)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; REPLICATE(&lt;span style="color:#006080;"&gt;'B'&lt;/span&gt;, 2048)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;INSERT dbo.T3 &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (TABLOCKX)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; REPLICATE(&lt;span style="color:#006080;"&gt;'C'&lt;/span&gt;, 2048)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;INSERT dbo.T4 &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (TABLOCKX)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; REPLICATE(&lt;span style="color:#006080;"&gt;'D'&lt;/span&gt;, 2048)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;INSERT dbo.T5 &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (TABLOCKX)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; REPLICATE(&lt;span style="color:#006080;"&gt;'E'&lt;/span&gt;, 2048)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;INSERT dbo.T6 &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (TABLOCKX)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; REPLICATE(&lt;span style="color:#006080;"&gt;'F'&lt;/span&gt;, 2048)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The next step is to ensure that each lookup table is optimally organized for read-ahead:&lt;/font&gt;&lt;/p&gt;

&lt;div id="codeSnippetWrapper" style="overflow:auto;cursor:text;font-size:8pt;border-top:silver 1px solid;font-family:'Courier New', courier, monospace;border-right:silver 1px solid;border-bottom:silver 1px solid;padding-bottom:4px;direction:ltr;text-align:left;padding-top:4px;padding-left:4px;margin:20px 0px 10px;border-left:silver 1px solid;line-height:12pt;padding-right:4px;max-height:200px;width:97.5%;background-color:#f4f4f4;"&gt;
  &lt;div id="codeSnippet" style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;
    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T1 REBUILD &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (MAXDOP = 1);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T2 REBUILD &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (MAXDOP = 1);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T3 REBUILD &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (MAXDOP = 1);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T4 REBUILD &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (MAXDOP = 1);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T5 REBUILD &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (MAXDOP = 1);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; dbo.T6 REBUILD &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (MAXDOP = 1);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;h3 align="left"&gt;Test Query&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The original query translates into our simplified test rig as:&lt;/font&gt;&lt;/p&gt;

&lt;div id="codeSnippetWrapper" style="overflow:auto;cursor:text;font-size:8pt;border-top:silver 1px solid;font-family:'Courier New', courier, monospace;border-right:silver 1px solid;border-bottom:silver 1px solid;padding-bottom:4px;direction:ltr;text-align:left;padding-top:4px;padding-left:4px;margin:20px 0px 10px;border-left:silver 1px solid;line-height:12pt;padding-right:4px;max-height:200px;width:97.5%;background-color:#f4f4f4;"&gt;
  &lt;div id="codeSnippet" style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;
    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @d nvarchar(&lt;span style="color:#0000ff;"&gt;max&lt;/span&gt;) = &lt;span style="color:#0000ff;"&gt;NCHAR&lt;/span&gt;(10000);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; n.n,&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;    DATALENGTH&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;    (&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;        CONCAT&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;        (&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;            (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; CONCAT(t.d, t.d, t.d, t.d, t.d, t.d, @d) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;            (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; CONCAT(t.d, t.d, t.d, t.d, t.d, t.d, @d) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;            (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; CONCAT(t.d, t.d, t.d, t.d, t.d, t.d, @d) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;            (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; CONCAT(t.d, t.d, t.d, t.d, t.d, t.d, @d) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;            (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; CONCAT(t.d, t.d, t.d, t.d, t.d, t.d, @d) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T5 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;            (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; CONCAT(t.d, t.d, t.d, t.d, t.d, t.d, @d) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T6 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;        )&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;    )&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n.n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; n.n&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt; (LOOP &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt;, FORCE &lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;, MAXDOP 1);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The broad idea there is to concatenate our 2048-character column to itself five times and include a Unicode character that was used in the original query as a delimiter that could not appear in the source data. Each lookup performs the same basic operation against its target table, and the final result is the result of concatenating all the intermediate results. The query hints are necessary to get the right plan shape, just because my test rig tables are so much smaller than the real ones.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;Note that the Unicode delimiter means the 2048-character single-byte data is implicitly converted to Unicode, doubling in size. It is not a crucial feature of the test, but it did appear in the original query and explains the type conversion warnings in the execution plan I mentioned earlier. The execution plan for the test query is (click to enlarge if necessary):&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_687DAD00.png" target="_blank"&gt;&lt;img title="Test query execution plan" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Test query execution plan" src="http://sqlblog.com/blogs/paul_white/image_thumb_50B64FCD.png" width="644" height="233" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;I should also stress that the CONCAT operator (new in SQL Server 2012) is not crucial either. If you are using an earlier version of SQL Server, an equivalent query (for present purposes) is shown below. I’m going to stick with CONCAT for the remainder of the post, however.&lt;/font&gt;&lt;/p&gt;

&lt;div id="codeSnippetWrapper" style="overflow:auto;cursor:text;font-size:8pt;border-top:silver 1px solid;font-family:'Courier New', courier, monospace;border-right:silver 1px solid;border-bottom:silver 1px solid;padding-bottom:4px;direction:ltr;text-align:left;padding-top:4px;padding-left:4px;margin:20px 0px 10px;border-left:silver 1px solid;line-height:12pt;padding-right:4px;max-height:200px;width:97.5%;background-color:#f4f4f4;"&gt;
  &lt;div id="codeSnippet" style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;
    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @d nvarchar(&lt;span style="color:#0000ff;"&gt;max&lt;/span&gt;) = &lt;span style="color:#0000ff;"&gt;NCHAR&lt;/span&gt;(10000);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; n.n,&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;    DATALENGTH&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;    (&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;        (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @d+t.d+t.d+t.d+t.d+t.d+t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) +&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;        (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @d+t.d+t.d+t.d+t.d+t.d+t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) +&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;        (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @d+t.d+t.d+t.d+t.d+t.d+t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) +&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;        (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @d+t.d+t.d+t.d+t.d+t.d+t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) +&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;        (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @d+t.d+t.d+t.d+t.d+t.d+t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T5 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) +&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;        (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @d+t.d+t.d+t.d+t.d+t.d+t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T6 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;    )&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n.n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; n.n&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt; (LOOP &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt;, FORCE &lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;, MAXDOP 1);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;h3 align="left"&gt;Warm cache results&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;With all data in memory, the test query (in either form) completes in about &lt;strong&gt;1.6 seconds&lt;/strong&gt; on my laptop. The result shows that each output row contains 147,468 bytes of Unicode character data. A typical set of I/O statistics follows:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_5B933115.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_25420906.png" width="534" height="164" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;Nothing too exciting to see there, but this is just our baseline.&lt;/font&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Cold cache results&lt;/h3&gt;

&lt;div id="codeSnippetWrapper" style="overflow:auto;cursor:text;font-size:8pt;border-top:silver 1px solid;font-family:'Courier New', courier, monospace;border-right:silver 1px solid;border-bottom:silver 1px solid;padding-bottom:4px;direction:ltr;text-align:left;padding-top:4px;padding-left:4px;margin:20px 0px 10px;border-left:silver 1px solid;line-height:12pt;padding-right:4px;max-height:200px;width:97.5%;background-color:#f4f4f4;"&gt;
  &lt;div id="codeSnippet" style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;
    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;CHECKPOINT&lt;/span&gt;;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;DBCC&lt;/span&gt; DROPCLEANBUFFERS;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;With no data in memory, the test query now runs for &lt;strong&gt;18.6 seconds&lt;/strong&gt; – almost &lt;strong&gt;12x slower&lt;/strong&gt;. The I/O statistics show the expected (but still mysterious!) work table and its associated reads:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_23913D32.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_5680CD99.png" width="646" height="182" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The Extended Events wait statistics show SQL Server spent very little of that time waiting on my laptop’s slow hard drive – just 402 ms:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_54D001C5.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_4C6C2C6E.png" width="292" height="131" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 align="left"&gt;Explanation&lt;/h2&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The are a number of factors in play here that we will look at in turn.&lt;/font&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Nested Loops Prefetching&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;One of the reasons the optimizer prefers Hash Match and Merge Join for larger inputs is that the data access patterns tend to favour large sequential read-ahead. Both hash and merge tend to scan (range-scan in the case of a seek) their inputs, and the SQL Server Storage Engine automatically issues read-ahead when it detects this type of access. There is nothing in the execution plan to show that a base table will be read with read-ahead, it just happens.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;A very basic implementation of Nested Loops join would not benefit from read-ahead at all on its inner side. The outer (driving) side of the loops join might well be a scan or range-scan of an index, and so benefit from automatic read-ahead, of course. The inner side is executed once per outer row, resulting in a rapid succession of small index seeks for different values. These small seeks will typically not be large enough to trigger the automatic read-ahead mechanism. Indeed, in our test, each inner side seek is for precisely one value.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;SQL Server improves on this by implementing a second read-ahead mechanism especially for Nested Loops joins (not all N-L joins, it is a cost-based decision the optimizer makes). The basic idea is to buffer extra rows from the outer side of the join, and to use the row values in the buffer to drive read-ahead for the inner side. The effect is that the Nested Loops join becomes a partly blocking operator as outer-side rows are read into the buffer and read-ahead issued based on buffered index key values.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;This read-ahead may be either order-preserving or not, and is indicated in the execution plan by the Nested Loop attributes &lt;em&gt;With Ordered Prefetch&lt;/em&gt; and &lt;em&gt;With Unordered Prefetch,&lt;/em&gt; respectively. When unordered prefetch occurs, the inner side is processed in whatever order the asynchronous reads happen to complete. With ordered prefetching, the mechanism is careful to ensure that the order of rows entering the join is preserved on the output.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;In the test rig, the ORDER BY clause means there is a need to preserve row order, so &lt;em&gt;Ordered Prefetch&lt;/em&gt; is used:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_58F9D98A.png" target="_blank"&gt;&lt;img title="Ordered Prefetch" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Ordered Prefetch" src="http://sqlblog.com/blogs/paul_white/image_thumb_612DFF21.png" width="644" height="379" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The issue described in this post is &lt;strong&gt;not specific to ordered prefetching&lt;/strong&gt; – the same behaviour is just as likely with unordered prefetching. The point is that Nested Loops prefetching is one of the requirements.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;&lt;a href="http://support.microsoft.com/kb/920093" target="_blank"&gt;Documented&lt;/a&gt; trace flags 652 and 8744 may be used (with care, and after serious testing) to disable automatic read-ahead and Nested Loops prefetching respectively. This is sometimes beneficial where all data is expected to be in memory (in which case read-ahead processing consumes resources better used by query execution) or where the I/O subsystem is &lt;em&gt;extremely&lt;/em&gt; fast. In case you were wondering, there is no background thread for prefetching – all the work of checking whether the data is in memory, and issuing I/O if not, is performed by the worker thread executing the query.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;I should stress that read-ahead and Nested Loops prefetching is generally A Very Good Thing with typical storage solutions (e.g. SANs) and both work best (or at all) when indexes have low logical fragmentation.&lt;/font&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Manufactured LOBs&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The issue described here also requires that a large object data type is manufactured before prefetching. The Compute Scalar operators in the test execution plan perform that function:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_10BBF7E1.png"&gt;&lt;img title="Manufactured LOB" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Manufactured LOB" src="http://sqlblog.com/blogs/paul_white/image_thumb_00CCB31D.png" width="599" height="314" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;By ‘manufactured’, I mean that the source columns are not LOB types, but the expression output is – notice the implicit conversion to nvarchar(max). To be clear about it, the issue we are analysing here does &lt;strong&gt;not&lt;/strong&gt; occur when Nested Loops prefetching occurs with an expression that was a LOB type to begin with.&lt;/font&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;The Outer Join&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The optimizer is quite good, generally speaking, at moving scalar expressions around. If the query had featured inner joins (whether by query design or through optimizer activities) the chances are quite good that the problematic expressions (the LOB manufacturers) would have moved beyond the prefetching, and so out of harm’s way. It is quite tricky to preserve NULL-extension and other outer-join semantics properly when moving expressions above an outer join, so the optimizer generally does not even try. In essence, the outer join represents an optimization barrier to the LOB-manufacturing expressions.&lt;/font&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Memory Allocation&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;When Nested Loops prefetching occurs with a manufactured LOB, the question arises of where to store the created LOBs when buffering rows for prefetch. If the source data were already a LOB type, the execution engine would already have memory structures in place to handle them. When prefetching encounters a manufactured LOB, it needs to store it somewhere, since the engine is no longer processing a stream of one row at a time. It turns out that there is a small memory buffer set aside for this eventuality, which empirical tests show to be 24KB.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;However, this 24KB (directly allocated, not via workspace memory grant) is shared across all concurrently executing prefetching joins in the query. With six such joins in the test rig plan and large manufactured LOBs, the buffer stands no chance. As a result, query execution engages a &lt;strong&gt;bail-out option&lt;/strong&gt;: a work table created in tempdb. Though the pages of the worktable may in fact remain memory-resident, overheads (including latching and using general-purpose code interfaces for access to the buffered rows) mean this is very much slower than using the direct-memory cache.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;As with most internal work tables, the logical reads reported on this work table indicate the number of &lt;strong&gt;rows&lt;/strong&gt; processed (not 8KB pages, as for regular I/O statistics). This fact, together with the large number of items processed via the worktable in our test, accounts for the millions of reads reported.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The creation and use of the work table depends on run time conditions and timing. If execution finds the data it needs is already in memory, the prefetch checks are still performed, but no asynchronous read requests end up being posted. The 24KB buffer is never filled, so the need to create a work table never arises. The more prefetch that &lt;em&gt;actually occurs&lt;/em&gt;, the higher the chances that the buffer will fill. It is quite possible to experience a low level of prefetch with manufactured LOBs without the engine needing to bail out to a work table, especially if the LOBs are not very big and the I/O system is quite fast.&lt;/font&gt;&lt;/p&gt;

&lt;h2 align="left"&gt;Workaround&lt;/h2&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;We can rewrite the query to avoid feeding manufactured LOB data to the prefetch buffer. The idea is to use OUTER APPLY to return the data that &lt;em&gt;contributes&lt;/em&gt; to the concatenation, rather than the &lt;em&gt;result&lt;/em&gt; of the concatenation. We can then perform the &lt;a href="http://msdn.microsoft.com/en-us/library/hh231515.aspx" target="_blank"&gt;CONCAT&lt;/a&gt; operation (which handles NULLs nicely without extra work) after the join, avoiding the prefetch buffer issue completely. In SQL Server versions prior to 2012, we would need to use direct string concatenation, and handle rows that are NULL-extended explicitly using ISNULL or COALESCE.&lt;/font&gt;&lt;/p&gt;

&lt;div id="codeSnippetWrapper" style="overflow:auto;cursor:text;font-size:8pt;border-top:silver 1px solid;font-family:'Courier New', courier, monospace;border-right:silver 1px solid;border-bottom:silver 1px solid;padding-bottom:4px;direction:ltr;text-align:left;padding-top:4px;padding-left:4px;margin:20px 0px 10px;border-left:silver 1px solid;line-height:12pt;padding-right:4px;max-height:200px;width:97.5%;background-color:#f4f4f4;"&gt;
  &lt;div id="codeSnippet" style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;
    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @d nvarchar(&lt;span style="color:#0000ff;"&gt;max&lt;/span&gt;) = &lt;span style="color:#0000ff;"&gt;NCHAR&lt;/span&gt;(10000);&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;    n.n,&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;    DATALENGTH&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;    (&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;        CONCAT&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;        (&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;            CONCAT(oa1.i0, oa1.i1, oa1.i2, oa1.i3, oa1.i4, oa1.i5, oa1.i6),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;            CONCAT(oa2.i0, oa2.i1, oa2.i2, oa2.i3, oa2.i4, oa2.i5, oa2.i6),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;            CONCAT(oa3.i0, oa3.i1, oa3.i2, oa3.i3, oa3.i4, oa3.i5, oa3.i6),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;            CONCAT(oa4.i0, oa4.i1, oa4.i2, oa4.i3, oa4.i4, oa4.i5, oa4.i6),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;            CONCAT(oa5.i0, oa5.i1, oa5.i2, oa5.i3, oa5.i4, oa5.i5, oa5.i6),&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;            CONCAT(oa6.i0, oa6.i1, oa6.i2, oa6.i3, oa6.i4, oa6.i5, oa6.i6)&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;        )&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;    )&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.Numbers &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; n&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;OUTER&lt;/span&gt; APPLY (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; i0 = @d, i1 = t.d, i2 = t.d, i3 = t.d, i4 = t.d, i5 = t.d, i6 = t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; oa1&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;OUTER&lt;/span&gt; APPLY (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; i0 = @d, i1 = t.d, i2 = t.d, i3 = t.d, i4 = t.d, i5 = t.d, i6 = t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; oa2&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;OUTER&lt;/span&gt; APPLY (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; i0 = @d, i1 = t.d, i2 = t.d, i3 = t.d, i4 = t.d, i5 = t.d, i6 = t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; oa3&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;OUTER&lt;/span&gt; APPLY (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; i0 = @d, i1 = t.d, i2 = t.d, i3 = t.d, i4 = t.d, i5 = t.d, i6 = t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; oa4&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;OUTER&lt;/span&gt; APPLY (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; i0 = @d, i1 = t.d, i2 = t.d, i3 = t.d, i4 = t.d, i5 = t.d, i6 = t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T5 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; oa5&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;OUTER&lt;/span&gt; APPLY (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; i0 = @d, i1 = t.d, i2 = t.d, i3 = t.d, i4 = t.d, i5 = t.d, i6 = t.d &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; dbo.T6 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; t.id = n.n) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; oa6&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; n.n &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 10000&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:white;"&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; n.n&lt;/pre&gt;


    &lt;pre style="border-top-style:none;overflow:visible;font-size:8pt;border-left-style:none;font-family:'Courier New', courier, monospace;border-bottom-style:none;color:black;padding-bottom:0px;direction:ltr;text-align:left;padding-top:0px;border-right-style:none;padding-left:0px;margin:0em;line-height:12pt;padding-right:0px;width:100%;background-color:#f4f4f4;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt; (LOOP &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt;, FORCE &lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;, MAXDOP 1);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The execution plan for the rewritten query looks visually similar to the problematic one:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_2C30D417.png" target="_blank"&gt;&lt;img title="Rewritten query plan" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="Rewritten query plan" src="http://sqlblog.com/blogs/paul_white/image_thumb_401A40E0.png" width="644" height="245" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;However, the Compute Scalars no longer manufacture a LOB data type, they just emit column and variable references:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_444418A5.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_3B07DD64.png" width="389" height="388" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;All the concatenation work (and LOB manufacture) is performed by the final top-level Compute Scalar in a single monster expression [Expr1056]:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_31CBA223.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_2E6A0A7B.png" width="697" height="419" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Warm cache results&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;With all data in memory, the new query completes in &lt;strong&gt;1.8 seconds&lt;/strong&gt; (very slightly up on 1.6 seconds before):&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_0B59990B.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_5ED06924.png" width="430" height="165" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Cold cache results&lt;/h3&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;When all data must be fetched from disk, the query issues optimal prefetching and completes in &lt;strong&gt;7.3 seconds&lt;/strong&gt; (down from 18.6 seconds) with &lt;strong&gt;no work table&lt;/strong&gt;:&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_0F173DDB.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_0D667207.png" width="536" height="165" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The Extended Events wait statistics now show 3.8 seconds spent waiting for my laptop’s slow spinning disk (which is a good thing!)&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_0BB5A633.png"&gt;&lt;img title="image" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/paul_white/image_thumb_1843534F.png" width="291" height="111" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 align="left"&gt;Final Thoughts&lt;/h2&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;Work tables can appear in STATISTICS IO output for a wide range of reasons, but if you encounter one with a very large number of reads – particularly LOB reads – you may be encountering this issue. The rewrite proposed above may not always be possible, but you should be able to refactor your query to avoid the issue now you know it exists.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;I am not a fan of doing large amounts of string manipulation in SQL Server. I am always particularly suspicious of the perceived need to split or concatenate large volumes of strings.&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;I am, however, a fan of always using explicit data types (rather than relying on implicit conversions) and generating relatively small query plans that offer the query optimizer clear and obvious choices. By necessity, this often means writing small SQL queries in logical steps (and no, long chains of common table expressions do not count!)&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;The real world does not always make these things possible, of course, but it is good to have goals :)&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;font size="3" face="Calibri"&gt;© 2013 Paul White – All Rights Reserved 
    &lt;br /&gt;email: &lt;a href="mailto:SQLkiwi@gmail.com"&gt;SQLkiwi@gmail.com&lt;/a&gt; 

    &lt;br /&gt;twitter: &lt;a href="http://twitter.com/SQL_Kiwi"&gt;@SQL_Kiwi&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p align="left"&gt;Screenshots acquired using &lt;a href="http://www.techsmith.com/snagit-gslp.html" target="_blank"&gt;SnagIt by TechSmith&lt;/a&gt;

  &lt;br /&gt;Query plan details obtained using &lt;a href="http://www.sqlsentry.net/plan-explorer/sql-server-query-view.asp#features" target="_blank"&gt;Plan Explorer PRO by SQLSentry&lt;/a&gt;&lt;/p&gt;</description></item><item><title>MERGE Bug with Filtered Indexes</title><link>http://sqlblog.com/blogs/paul_white/archive/2012/12/09/merge-bug-with-filtered-indexes.aspx</link><pubDate>Sun, 09 Dec 2012 17:54:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:46572</guid><dc:creator>Paul White</dc:creator><description>&lt;p align="left"&gt;A MERGE statement can fail, and incorrectly report a unique key violation when:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;div align="left"&gt;The target table uses a unique filtered index; and&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div align="left"&gt;No key column of the filtered index is updated; and&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div align="left"&gt;A column from the filtering condition is updated; and&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div align="left"&gt;Transient key violations are possible&lt;/div&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;h3 align="left"&gt;Example Tables&lt;/h3&gt;  &lt;p align="left"&gt;Say we have two tables, one that is the target of a MERGE statement, and another that contains updates to be applied to the target.&amp;#160; The target table contains three columns, an integer primary key, a single character alternate key, and a status code column.&amp;#160; A filtered unique index exists on the alternate key, but is only enforced where the status code is ‘a’:&lt;/p&gt;  &lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:300px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;     &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; #Target &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;(&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    pk          &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ak          &lt;span style="color:#0000ff;"&gt;character&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    status_code &lt;span style="color:#0000ff;"&gt;character&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; (pk)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;);&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;UNIQUE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;INDEX&lt;/span&gt; uq1&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt; #Target (ak)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;INCLUDE&lt;/span&gt; (status_code)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; status_code = &lt;span style="color:#006080;"&gt;'a'&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;The changes table contains just an integer primary key (to identify the target row to change) and the new status code:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; #Changes&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;(&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    pk          &lt;span style="color:#0000ff;"&gt;integer&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    status_code &lt;span style="color:#0000ff;"&gt;character&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; (pk)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;h3 align="left"&gt;Sample Data&lt;/h3&gt;

&lt;p align="left"&gt;The sample data for the example is:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;INSERT #Target &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (pk, ak, status_code)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (1, &lt;span style="color:#006080;"&gt;'A'&lt;/span&gt;, &lt;span style="color:#006080;"&gt;'a'&lt;/span&gt;),&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (2, &lt;span style="color:#006080;"&gt;'B'&lt;/span&gt;, &lt;span style="color:#006080;"&gt;'a'&lt;/span&gt;),&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (3, &lt;span style="color:#006080;"&gt;'C'&lt;/span&gt;, &lt;span style="color:#006080;"&gt;'a'&lt;/span&gt;),&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (4, &lt;span style="color:#006080;"&gt;'A'&lt;/span&gt;, &lt;span style="color:#006080;"&gt;'d'&lt;/span&gt;);&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;INSERT #Changes&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (pk, status_code)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (1, &lt;span style="color:#006080;"&gt;'d'&lt;/span&gt;),&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (4, &lt;span style="color:#006080;"&gt;'a'&lt;/span&gt;);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;b&gt;Target&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Changes&lt;/b&gt; 

    &lt;br /&gt;╔════╦════╦═════════════╗&amp;#160;&amp;#160;&amp;#160; ╔════╦═════════════╗ 

    &lt;br /&gt;║ pk ║ ak ║ status_code ║&amp;#160;&amp;#160;&amp;#160; ║ pk ║ status_code ║ 

    &lt;br /&gt;╠════╬════╬═════════════╣&amp;#160;&amp;#160;&amp;#160; ╠════╬═════════════╣ 

    &lt;br /&gt;║&amp;#160; 1 ║ A&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 1 ║ d&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 2 ║ B&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 4 ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 3 ║ C&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ╚════╩═════════════╝ 

    &lt;br /&gt;║&amp;#160; 4 ║ A&amp;#160; ║ d&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;╚════╩════╩═════════════╝&lt;/font&gt; 

  &lt;br /&gt;&lt;/p&gt;

&lt;p align="left"&gt;The target table’s alternate key (ak) column is unique, for rows where status_code = ‘a’.&amp;#160; Applying the changes to the target will change row 1 from status ‘a’ to status ‘d’, and row 4 from status ‘d’ to status ‘a’.&amp;#160; The result of applying all the changes will still satisfy the filtered unique index, because the ‘A’ in row 1 will be deleted from the index and the ‘A’ in row 4 will be added.&lt;/p&gt;

&lt;h3 align="left"&gt;Merge Test One&lt;/h3&gt;

&lt;p align="left"&gt;Let’s now execute a MERGE statement to apply the changes:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;MERGE #Target &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;USING&lt;/span&gt; #Changes &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; c &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    c.pk = t.pk&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; MATCHED &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; c.status_code &amp;lt;&amp;gt; t.status_code &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; status_code = c.status_code;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;The MERGE changes the two target rows as expected.&amp;#160; The updated target table now contains:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;╔════╦════╦═════════════╗ 
    &lt;br /&gt;║ pk ║ ak ║ status_code ║ 

    &lt;br /&gt;╠════╬════╬═════════════╣ 

    &lt;br /&gt;║&amp;#160; 1 ║ A&amp;#160; ║ &lt;b&gt;&lt;font color="#ff0000"&gt;d&lt;/font&gt;&lt;/b&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ &amp;lt;—changed from ‘a’ 

    &lt;br /&gt;║&amp;#160; 2 ║ B&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 3 ║ C&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 4 ║ A&amp;#160; ║ &lt;b&gt;&lt;font color="#ff0000"&gt;a&lt;/font&gt;&lt;/b&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ &amp;lt;—changed from ‘d’ 

    &lt;br /&gt;╚════╩════╩═════════════╝&lt;/font&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Merge Test Two&lt;/h3&gt;

&lt;p align="left"&gt;Now let’s repopulate the changes table to reverse the updates we just performed:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;TRUNCATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; #Changes;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;INSERT #Changes&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (pk, status_code)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (1, &lt;span style="color:#006080;"&gt;'a'&lt;/span&gt;),&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    (4, &lt;span style="color:#006080;"&gt;'d'&lt;/span&gt;);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;This will change row 1 back to status ‘a’ and row 4 back to status ‘d’.&amp;#160; As a reminder, the current state of the tables is:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;b&gt;Target&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Changes&lt;/b&gt; 

    &lt;br /&gt;╔════╦════╦═════════════╗&amp;#160;&amp;#160;&amp;#160; ╔════╦═════════════╗ 

    &lt;br /&gt;║ pk ║ ak ║ status_code ║&amp;#160;&amp;#160;&amp;#160; ║ pk ║ status_code ║ 

    &lt;br /&gt;╠════╬════╬═════════════╣&amp;#160;&amp;#160;&amp;#160; ╠════╬═════════════╣ 

    &lt;br /&gt;║&amp;#160; 1 ║ A&amp;#160; ║ d&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 1 ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 2 ║ B&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 4 ║ d&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 3 ║ C&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ╚════╩═════════════╝ 

    &lt;br /&gt;║&amp;#160; 4 ║ A&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;╚════╩════╩═════════════╝&lt;/font&gt; 

  &lt;br /&gt;&lt;/p&gt;

&lt;p align="left"&gt;We execute the same MERGE statement:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;MERGE #Target &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;USING&lt;/span&gt; #Changes &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; c &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    c.pk = t.pk&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; MATCHED &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; c.status_code &amp;lt;&amp;gt; t.status_code &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; status_code = c.status_code;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;However this time we receive the following message:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;font face="Courier New"&gt;&lt;font color="#ff0000"&gt;Msg 2601, Level 14, State 1, Line 1 
        &lt;br /&gt;Cannot insert duplicate key row in object 'dbo.#Target' with unique index 'uq1'. The duplicate key value is (A). 

        &lt;br /&gt;&lt;/font&gt;The statement has been terminated.&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Applying the changes using UPDATE&lt;/h3&gt;

&lt;p align="left"&gt;Let’s now rewrite the MERGE to use UPDATE instead:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;UPDATE&lt;/span&gt; t&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; status_code = c.status_code&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; #Target &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; t&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; #Changes &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; c &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    t.pk = c.pk&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    c.status_code &amp;lt;&amp;gt; t.status_code;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This query succeeds where the MERGE failed.&amp;#160; The two rows are updated as expected:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;╔════╦════╦═════════════╗ 
    &lt;br /&gt;║ pk ║ ak ║ status_code ║ 

    &lt;br /&gt;╠════╬════╬═════════════╣ 

    &lt;br /&gt;║&amp;#160; 1 ║ A&amp;#160; ║ &lt;b&gt;&lt;font color="#ff0000"&gt;a&lt;/font&gt;&lt;/b&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ &amp;lt;—changed back to ‘a’ 

    &lt;br /&gt;║&amp;#160; 2 ║ B&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 3 ║ C&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 4 ║ A&amp;#160; ║ &lt;b&gt;&lt;font color="#ff0000"&gt;d&lt;/font&gt;&lt;/b&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ &amp;lt;—changed back to ‘d’ 

    &lt;br /&gt;╚════╩════╩═════════════╝&lt;/font&gt;&lt;/p&gt;

&lt;h3&gt;What went wrong with the MERGE?&lt;/h3&gt;

&lt;p align="left"&gt;In this test, the MERGE query execution happens to apply the changes in the order of the ‘pk’ column.&lt;/p&gt;

&lt;p align="left"&gt;&lt;b&gt;In test one, this was not a problem&lt;/b&gt;: row 1 is removed from the unique filtered index by changing status_code from ‘a’ to ‘d’ before row 4 is added.&amp;#160; At no point does the table contain two rows where ak = ‘A’ and status_code = ‘a’.&lt;/p&gt;

&lt;p align="left"&gt;&lt;b&gt;In test two, however&lt;/b&gt;, the first change was to change row 1 from status ‘d’ to status ‘a’.&amp;#160; This change means there would be two rows in the filtered unique index where ak = ‘A’ (both row 1 and row 4 meet the index filtering criteria ‘status_code = a’).&lt;/p&gt;

&lt;p align="left"&gt;The storage engine does not allow the query processor to violate a unique key (unless IGNORE_DUP_KEY is ON, but that is a different story, and doesn’t apply to MERGE in any case).&amp;#160; This strict rule applies regardless of the fact that if &lt;b&gt;all&lt;/b&gt; changes were applied, there would be no unique key violation (row 4 would eventually be changed from ‘a’ to ‘d’, removing it from the filtered unique index, and resolving the key violation).&lt;/p&gt;

&lt;h3 align="left"&gt;Why it went wrong&lt;/h3&gt;

&lt;p align="left"&gt;The query optimizer usually detects when this sort of &lt;b&gt;temporary uniqueness violation&lt;/b&gt; could occur, and builds a plan that avoids the issue.&amp;#160; I wrote about this a couple of years ago in my post &lt;a href="http://bit.ly/SneakyReads" target="_blank"&gt;Beware Sneaky Reads with Unique Indexes&lt;/a&gt; (you can read more about the details on pages 495-497 of &lt;a href="http://www.microsoft.com/learning/en/us/book.aspx?id=12967" target="_blank"&gt;Microsoft SQL Server 2008 Internals&lt;/a&gt; or in Craig Freedman’s &lt;a href="http://blogs.msdn.com/b/craigfr/archive/2007/09/06/maintaining-unique-indexes.aspx" target="_blank"&gt;blog post&lt;/a&gt; on maintaining unique indexes).&amp;#160; To summarize though, the optimizer introduces &lt;b&gt;Split, Filter, Sort, and Collapse&lt;/b&gt; operators into the query plan to:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;div align="left"&gt;&lt;b&gt;Split&lt;/b&gt; each row update into delete followed by an inserts&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;&lt;b&gt;Filter&lt;/b&gt; out rows that would not change the index (due to the filter on the index, or a &lt;a href="http://bit.ly/NonUpdatingUpdates" target="_blank"&gt;non-updating update&lt;/a&gt;)&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;&lt;b&gt;Sort&lt;/b&gt; the resulting stream by index key, with deletes before inserts&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;&lt;b&gt;Collapse&lt;/b&gt; delete/insert pairs on the same index key back into an update&lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p align="left"&gt;The effect of all this is that &lt;b&gt;only net changes are applied&lt;/b&gt; to an index (as one or more insert, update, and/or delete operations).&amp;#160; In this case, the net effect is a single update of the filtered unique index: changing the row for ak = ‘A’ from pk = 4 to pk = 1.&amp;#160; In case that is less than 100% clear, let’s look at the operation in test two again:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;b&gt;Target&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Changes&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Result&lt;/b&gt; 

    &lt;br /&gt;╔════╦════╦═════════════╗&amp;#160;&amp;#160;&amp;#160; ╔════╦═════════════╗&amp;#160;&amp;#160;&amp;#160; ╔════╦════╦═════════════╗ 

    &lt;br /&gt;║ pk ║ ak ║ status_code ║&amp;#160;&amp;#160;&amp;#160; ║ pk ║ status_code ║&amp;#160;&amp;#160;&amp;#160; ║ pk ║ ak ║ status_code ║ 

    &lt;br /&gt;╠════╬════╬═════════════╣&amp;#160;&amp;#160;&amp;#160; ╠════╬═════════════╣&amp;#160;&amp;#160;&amp;#160; ╠════╬════╬═════════════╣ 

    &lt;br /&gt;║&amp;#160; 1 ║ A&amp;#160; ║ d&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 1 ║ d&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 1 ║ A&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 2 ║ B&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 4 ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 2 ║ B&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 3 ║ C&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ╚════╩═════════════╝&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 3 ║ C&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 4 ║ A&amp;#160; ║ a&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 4 ║ A&amp;#160; ║ d&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ║ 

    &lt;br /&gt;╚════╩════╩═════════════╝&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ╚════╩════╩═════════════╝&lt;/font&gt; 

  &lt;br /&gt;&lt;/p&gt;

&lt;p align="left"&gt;From the &lt;b&gt;filtered index’s point of view&lt;/b&gt; (filtered for status_code = ‘a’ and shown in nonclustered index key order) the overall effect of the query is:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;&lt;b&gt;&amp;#160; Before&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; After 
      &lt;br /&gt;&lt;/b&gt;╔════╦════╗&amp;#160;&amp;#160;&amp;#160; ╔════╦════╗ 

    &lt;br /&gt;║ pk ║ ak ║&amp;#160;&amp;#160;&amp;#160; ║ pk ║ ak ║ 

    &lt;br /&gt;╠════╬════╣&amp;#160;&amp;#160;&amp;#160; ╠════╬════╣ 

    &lt;br /&gt;║&amp;#160; &lt;font color="#ff0000"&gt;&lt;b&gt;4&lt;/b&gt;&lt;/font&gt; ║ A&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; &lt;b&gt;&lt;font color="#ff0000"&gt;1&lt;/font&gt;&lt;/b&gt; ║ A&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 2 ║ B&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 2 ║ B&amp;#160; ║ 

    &lt;br /&gt;║&amp;#160; 3 ║ C&amp;#160; ║&amp;#160;&amp;#160;&amp;#160; ║&amp;#160; 3 ║ C&amp;#160; ║ 

    &lt;br /&gt;╚════╩════╝&amp;#160;&amp;#160;&amp;#160; ╚════╩════╝&lt;/font&gt; 

  &lt;br /&gt;&lt;/p&gt;

&lt;p align="left"&gt;The &lt;b&gt;single net change&lt;/b&gt; there is a change of pk from 4 to 1 for the nonclustered index entry ak = ‘A’.&amp;#160; This is the magic performed by the split, sort, and collapse.&amp;#160; Notice in particular how the original changes to the index key (on the ‘ak’ column) have been transformed into an update of a non-key column (pk is included in the nonclustered index).&amp;#160; By not updating any nonclustered index keys, we are &lt;b&gt;guaranteed to avoid transient key violations&lt;/b&gt;.&lt;/p&gt;

&lt;h3 align="left"&gt;The Execution Plans&lt;/h3&gt;

&lt;p align="left"&gt;The estimated MERGE execution plan that produces the &lt;b&gt;incorrect key-violation error&lt;/b&gt; looks like this (click to enlarge in a new window):&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_0C120630.png" target="_blank"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="MERGE plan" border="0" alt="MERGE plan" src="http://sqlblog.com/blogs/paul_white/image_thumb_7BB68E76.png" width="660" height="142" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;The successful UPDATE execution plan is (click to enlarge in a new window):&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_58A61D06.png" target="_blank"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="UPDATE execution plan" border="0" alt="UPDATE execution plan" src="http://sqlblog.com/blogs/paul_white/image_thumb_15E6D1CE.png" width="660" height="111" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;The MERGE execution plan is a &lt;b&gt;narrow&lt;/b&gt; (per-row) update.&amp;#160; The single Clustered Index Merge operator maintains both the clustered index and the filtered nonclustered index.&amp;#160; The UPDATE plan is a &lt;b&gt;wide&lt;/b&gt; (per-index) update.&amp;#160; The clustered index is maintained first, then the Split, Filter, Sort, Collapse sequence is applied before the nonclustered index is separately maintained.&lt;/p&gt;

&lt;p align="left"&gt;&lt;b&gt;There is always a wide update plan&lt;/b&gt; for any query that modifies the database. The narrow form is a performance optimization where the number of rows is expected to be relatively small, and is not available for all operations.&amp;#160; One of the operations that &lt;b&gt;should disallow a narrow plan&lt;/b&gt; is maintaining a unique index where intermediate key violations could occur.&lt;/p&gt;

&lt;h3 align="left"&gt;Workarounds&lt;/h3&gt;

&lt;p align="left"&gt;The MERGE can be made to work (producing a wide update plan with split, sort, and collapse) by:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;div align="left"&gt;Adding all columns referenced in the filtered index’s WHERE clause to the index key (INCLUDE is not sufficient); or&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Executing the query with trace flag 8790 set e.g. OPTION (QUERYTRACEON 8790).&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p align="left"&gt;Undocumented trace flag 8790 forces a wide update plan for any data-changing query (remember that a wide update plan is always possible).&amp;#160; Either change will produce a successfully-executing wide update plan for the MERGE that failed previously.&lt;/p&gt;

&lt;h3 align="left"&gt;Conclusion&lt;/h3&gt;

&lt;p align="left"&gt;The optimizer fails to spot the possibility of transient unique key violations with MERGE under the conditions listed at the start of this post.&amp;#160; It incorrectly chooses a narrow plan for the MERGE, which cannot provide the protection of a split/sort/collapse sequence for the nonclustered index maintenance.&lt;/p&gt;

&lt;p align="left"&gt;The MERGE plan may fail at execution time depending on the order in which rows are processed, and the distribution of data in the database.&amp;#160; Worse, a previously solid MERGE query may &lt;b&gt;suddenly start to fail unpredictably&lt;/b&gt; if a filtered unique index is added to the merge target table at any point.&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/773895/merge-incorrectly-reports-unique-key-violations" target="_blank"&gt;Connect bug filed here&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;i&gt;Bug reproduced on the following SQL Server versions (all x64 Developer Edition):&lt;/i&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;i&gt;&lt;strong&gt;2012 SP1 CUI&lt;/strong&gt; (build 11.0.3321 – November 2012)

    &lt;br /&gt;&lt;strong&gt;2008 R2 SP2 CU3&lt;/strong&gt; (build 10.50.4266 – October 2012)

    &lt;br /&gt;&lt;strong&gt;2008 SP3 CU8 &lt;/strong&gt;(build 10.0.5828 – November 2012)&lt;/i&gt;&lt;/p&gt;

&lt;p align="left"&gt;© 2012 Paul White – All Rights Reserved&lt;/p&gt;

&lt;p align="left"&gt;Twitter: &lt;a href="http://twitter.com/SQL_Kiwi"&gt;@SQL_Kiwi&lt;/a&gt; 

  &lt;br /&gt;Email: &lt;a href="mailto:SQLkiwi@gmail.com"&gt;SQLkiwi@gmail.com&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Query Optimizer Deep Dive - Part 4</title><link>http://sqlblog.com/blogs/paul_white/archive/2012/04/30/query-optimizer-deep-dive-part-4.aspx</link><pubDate>Mon, 30 Apr 2012 13:36:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:43093</guid><dc:creator>Paul White</dc:creator><description>&lt;p align="left"&gt;This is the final part in a series of posts based on the content of the &lt;i&gt;Query Optimizer Deep Dive&lt;/i&gt; presentations I have given over the last month or so at the &lt;a target="_blank" href="http://www.aucklandsql.com"&gt;Auckland SQL Users’ Group&lt;/a&gt; and the SQL Saturday events in &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=136&amp;amp;sessionid=8411"&gt;Wellington, New Zealand&lt;/a&gt; and &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=139&amp;amp;sessionid=8412"&gt;Adelaide, Australia&lt;/a&gt;.&lt;/p&gt;  &lt;p align="left"&gt;Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx"&gt;Part 1&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-2.aspx"&gt;Part 2&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx"&gt;Part 3&lt;/a&gt;&lt;/p&gt;  &lt;h3 align="left"&gt;Beating the Optimizer&lt;/h3&gt;  &lt;p align="left"&gt;Our test query produces an optimized physical execution plan that is quite different from the logical form of the query.&amp;nbsp; The estimated cost of the execution plan shown below is &lt;b&gt;0.0295&lt;/b&gt; units.&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_7B3F183B.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Optimized Query Plan" border="0" alt="Optimized Query Plan" width="640" height="158" src="http://sqlblog.com/blogs/paul_white/image_thumb_3EC6A391.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;Since we know the database schema very well, we might wonder why the optimizer did not choose to use the unique nonclustered index on names in the product table to filter rows based on the LIKE predicate.&amp;nbsp; We could use an index hint to force the name index to be used:&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_69525EA1.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Forced Index Hint" border="0" alt="Forced Index Hint" width="640" height="159" src="http://sqlblog.com/blogs/paul_white/image_thumb_0A82547E.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;That’s great, and no doubt the index seek is cheaper than the scan we had previously, but the optimizer has still chosen to use a merge join, and that means having both inputs sorted on Product ID.&amp;nbsp; The result of the index seek is ordered by name (the index key) rather than Product ID, so a sort is required.&amp;nbsp; It looks like the new sort adds a little more cost than the seek saves over the scan, because the estimated cost of the query plan with the index hint is &lt;b&gt;0.0316&lt;/b&gt; units.&lt;/p&gt;  &lt;p align="left"&gt;Naturally, these numbers are rather small since AdventureWorks is not a large database, but these differences can be important in real systems.&amp;nbsp; Anyway, let’s persist with the index seek idea; why is the optimizer so keen on a merge join, even though it involves an extra sort, and we don’t have an ORDER BY Product ID clause on our query?&amp;nbsp; Without a top-level ORDER BY, we are giving the optimizer the freedom to return results in any order that is convenient – perhaps we can do better by forcing the index seek and a hash join instead of a merge join?&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_26CF969E.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Forced Hash Join" border="0" alt="Forced Hash Join" width="640" height="159" src="http://sqlblog.com/blogs/paul_white/image_thumb_1FCFE419.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;Well the sort has gone, so the plan looks visually a little simpler, but the estimated cost has increased again, to &lt;b&gt;0.0348&lt;/b&gt; units.&amp;nbsp; Hash join has quite a high start-up cost (and it requires a memory workspace grant).&amp;nbsp; We could try other things, but it certainly seems that the optimizer had it right to begin with in this case.&lt;/p&gt;  &lt;p align="left"&gt;The manual exploration above shows that the optimizer does generally find a good plan quickly (and sometimes it may even find the best possible plan). The terms ‘good’ and ‘best’ here are measured in terms of the optimizer’s own cost model. Whether one particular plan shape &lt;i&gt;actually&lt;/i&gt; executes faster on a given system is another question. I might find, for example, that the first merge join plan runs fastest for me, whereas you might find the seek and sort runs fastest for you. We might both find that which is faster depends on whether the indexes and data needed are in memory or need to be retrieved from persistent storage. All these things aside, the important thing is that we are both likely to find that the optimizer’s plans are pretty good most of the time.&lt;/p&gt;  &lt;h3&gt;Models and Limitations&lt;/h3&gt;  &lt;p align="left"&gt;There are three principal models used by the optimizer to provide a basis for its reasoning: cardinality estimation, logical relational equivalences, and physical operator costing.&amp;nbsp; Good cardinality estimation (row count expectations at each node of the logical tree) is vital; if these numbers are wrong, all later decisions are suspect.&amp;nbsp; Fortunately, it is relatively easy to check cardinality estimation by comparing actual and estimated row counts in query plans.&amp;nbsp; There are some subtleties to be aware of – for example when interpreting the inner side of a nested loops join, at least in SSMS.&amp;nbsp; If you use the free &lt;a target="_blank" href="http://www.sqlsentry.net/plan-explorer/sql-server-query-view.asp"&gt;SQL Sentry Plan Explorer&lt;/a&gt; tool, many of these common misinterpretations are handled for you.&lt;/p&gt;  &lt;p align="left"&gt;The model used in cardinality estimation is complex, and contains all sorts of hairy-looking formulas and calculations.&amp;nbsp; Nevertheless, it is still a model, and as such will deviate from reality at least to some extent.&amp;nbsp; I’ll have more to say later on about what we can do to help ensure good cardinality estimates, but for now we will just note that the model has its roots in relational theory and statistical analysis.&lt;/p&gt;  &lt;p align="left"&gt;Relational equivalences (such as A inner join B = B inner join A) are the basis for exploration rules in the cost-based optimizer.&amp;nbsp; Not all possible relational transformations are included in the product (remember the goal of the optimizer is to find a good plan quickly, not to perform an exhaustive search of all possible plans).&amp;nbsp; As a consequence, the SQL syntax you use will often affect the plan produced by the optimizer, even where different SQL syntaxes express the same logical requirement.&amp;nbsp; Also, the skilled query tuner will often be able to do better than the optimizer, given enough time and perhaps a better insight to the data.&amp;nbsp; The downside of such manual tuning is that it will usually require manual intervention again in the future as data volumes and distributions change.&lt;/p&gt;  &lt;p align="left"&gt;Physical operator costing is very much the simplest of the three models, using formulas that have been shown to produce good physical plan selections for a wide range of queries on a wide range of hardware.&amp;nbsp; The numbers used probably do not closely model your hardware or mine, but luckily that turns out not to be too important in most cases.&amp;nbsp; No doubt the model will have to be updated over time as new hardware trends continue to emerge, and there is some evidence in SQL Server 2012 show plan output that things are heading in that direction.&lt;/p&gt;  &lt;h4 align="left"&gt;Assumptions&lt;/h4&gt;  &lt;p align="left"&gt;All models make simplifying assumptions, and the cardinality estimation and costing models are no different.&amp;nbsp; Some things are just too hard to model, and other things just haven’t been incorporated into the model yet.&amp;nbsp; Still other things could be modelled, but turn out not to add much value in practice and cost too much in terms of complexity or resource consumption.&amp;nbsp; Some of the major simplifying assumptions that can affect real plan quality are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;div align="left"&gt;All queries start executing with a cold cache        &lt;br&gt;&lt;i&gt;This isn’t as crazy as it sounds.&amp;nbsp; Fetching data from disk tends to dominate the overall cost of a query, modelling the amount of data that can be expected to be in cache already is hard, and this assumption does at least affect everything equally.&amp;nbsp; The optimizer does contain some logic to account for pages that might be in cache after the first access.&lt;/i&gt;&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div align="left"&gt;Statistical information is independent        &lt;br&gt;&lt;i&gt;Correlations do frequently exist between columns in real databases, so this assumption can be problematic.&amp;nbsp; Multi-column statistics, filtered indexes, and indexed views can sometimes help with this.&lt;/i&gt;&lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;div align="left"&gt;Distribution is uniform        &lt;br&gt;&lt;i&gt;This is assumed where the system has no information to the contrary.&amp;nbsp; One example: costing assumes that seeks (lookups) into an index are randomly distributed throughout the full range of the index.&lt;/i&gt;&lt;/div&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Helping the Optimizer&lt;/h3&gt;  &lt;p&gt;There are three approaches to working with the optimizer:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Ignore it.&amp;nbsp; It works well out of the box with default settings and automatic statistics. &lt;/li&gt;    &lt;li&gt;Override it using syntax tricks, hints, and plan guides. &lt;/li&gt;    &lt;li&gt;Provide it with the best information you can, and override it for just a small number of problematic queries. &lt;/li&gt; &lt;/ol&gt;  &lt;p align="left"&gt;All three are valid approaches in different circumstances, though the third option is probably the one to recommend as the best starting point.&amp;nbsp; There is much more to helping the optimizer than just making sure statistics are up-to-date, however:&lt;/p&gt;  &lt;h4 align="left"&gt;Use a relational design&lt;/h4&gt;  &lt;p align="left"&gt;This is probably the biggest single item.&amp;nbsp; The various models all assume that your database has a reasonably relational design, not necessarily 3NF or higher, but the closer your structures are to relational principles, the better.&amp;nbsp; Cardinality estimation works best with simpler relational operations like joins, projects, selects, unions and group by.&amp;nbsp; Avoid complex expressions and non-relational query features that force cardinality estimation to guess.&amp;nbsp; Also remember that the cost-based optimizer’s exploration rules are based on relational equivalences, so having a relational design and writing relational queries gives you the best chance of leveraging the hard work that has gone into those rules.&amp;nbsp; Some features added in 2005 (e.g. ranking functions) operate on sequences rather than multi-sets (hence the Sequence Project physical operator); the original rules all work with multi-sets, and the seams between the two approaches often show though.&lt;/p&gt;  &lt;h4 align="left"&gt;Use constraints&lt;/h4&gt;  &lt;p align="left"&gt;Use check constraints, foreign keys, unique constraints to provide the optimizer with information about your data.&amp;nbsp; Simplification and exploration rules match patterns in the logical tree, and may also require certain properties to be set on the matched nodes.&amp;nbsp; Constraints and keys provide some of the most powerful and fundamental logical properties – omitting these can prevent many of the optimizer’s rules from successfully transforming to an efficient physical plan.&amp;nbsp; If an integer column should only contain certain values, add a check constraint for it.&amp;nbsp; If a foreign key relationship exists, enforce it.&amp;nbsp; If a key exists, declare it.&amp;nbsp; It is not always possible to predict the benefits of providing this type of optimizer information, but my own experience is that it is much greater than most people would ever expect.&lt;/p&gt;  &lt;h4 align="left"&gt;Statistics, indexes and computed columns&lt;/h4&gt;  &lt;p align="left"&gt;Provide more than just default-sampled automatically-created statistics where appropriate (for example where distribution is unusual or correlations exist).&amp;nbsp; Create indexes that will provide potentially useful access paths for a wide range of queries.&amp;nbsp; If you have expressions on columns in your WHERE clause, consider adding a computed column that matches the expression exactly.&amp;nbsp; The computed column does not have to be persisted or indexed to be useful; the system can auto-create statistics on the computed column, avoiding cardinality guessing.&lt;/p&gt;  &lt;h4 align="left"&gt;Deep Trees&lt;/h4&gt;  &lt;p align="left"&gt;Large, complex queries produce large, complex logical trees.&amp;nbsp; Any errors tend to multiply (perhaps exponentially) as the size of the tree increases, the search space of possible plans expands greatly, and things just become much more difficult in general.&amp;nbsp; Breaking a complex query into smaller, simpler, more relational, steps will generally get greater value out of the optimizer.&amp;nbsp; A side benefit is that small intermediate results stored in a temporary table can have statistics created, which will also help in many cases.&amp;nbsp; There will always be cases where a large complex query is required for ultimate performance, but very often the performance difference is relatively small and may not be worth the future maintenance costs as hand-tuned monolithic queries tend to be fragile.&lt;/p&gt;  &lt;h4 align="left"&gt;Opaque operators and new features&lt;/h4&gt;  &lt;p align="left"&gt;User-defined functions (other than the in-line variety) may seem convenient, but they are almost completely opaque to the optimizer – it has to guess at the cardinality and distribution of rows produced.&amp;nbsp; Newer features also tend to have much shallower support in the engine than longer-established features that have been around for multiple versions of the product.&amp;nbsp; By all means use all the shiny new features, just be aware that combining them may produce plans of variable quality.&lt;/p&gt;  &lt;h3 align="left"&gt;Trace Flags&lt;/h3&gt;  &lt;p align="left"&gt;To summarize the flags used in this series (all assume 3604 is also active):&lt;/p&gt;  &lt;p align="left"&gt;7352 : Final query tree    &lt;br&gt;8605 : Converted tree     &lt;br&gt;8606 : Input, simplified, join-collapsed, and normalized trees     &lt;br&gt;8607 : Output tree     &lt;br&gt;8608 : Initial memo     &lt;br&gt;8615 : Final memo     &lt;br&gt;8675 : Optimization stages and times&lt;/p&gt;  &lt;p align="left"&gt;The above were used in the presentation because they all work from 2005 to 2012.&amp;nbsp; There are a large number of other optimizer-related flags (some of which only work on 2012).&amp;nbsp; Some are listed below for people that like this sort of thing:&lt;/p&gt;  &lt;p align="left"&gt;2373 : Memory before and after deriving properties and rules (verbose)    &lt;br&gt;7357 : Unique hash optimization used     &lt;br&gt;8609 : Task and operation type counts     &lt;br&gt;8619 : Apply rule with description     &lt;br&gt;8620 : Add memo arguments to 8619     &lt;br&gt;8621 : Rule with resulting tree&lt;/p&gt;  &lt;p align="left"&gt;As usual, these are undocumented, and unsupported (including by me!) and purely for educational purposes.&amp;nbsp; Use with care at your own risk.&lt;/p&gt;  &lt;h3&gt;Final Thoughts&lt;/h3&gt;  &lt;p align="left"&gt;I hope you have gained some insight and intuition for the workings of the query optimizer: logical trees, simplification, cardinality estimation, logical exploration and physical implementation.&amp;nbsp; The geeky internals stuff is fun, of course, but I rather hope people came away from these sessions with a better understanding of how query text is transformed to an executable plan, and how relational designs and simpler queries can help the optimizer work well for you.&amp;nbsp; Taking advantage of the optimizer frees up time for more productive things – new projects, tuning the odd interesting query, whatever it is you would rather be doing than fighting the same query-tuning battles over and over again.&lt;/p&gt;  &lt;p align="left"&gt;There are some great resources out there to learn more about SQL Server. Make full use of them to continue to improve your technical skills and just as importantly, experiment with things to build your experience level. Take a deeper look at query plans and the properties they contain; there is a wealth of information there that sometimes requires a bit of thinking and research to understand, but the insights can be invaluable.&lt;/p&gt;  &lt;p align="left"&gt;The original slides and demo code is again attached as a zip file below.&amp;nbsp; Thanks for reading, all comments and feedback are very welcome.&lt;/p&gt;  &lt;p align="left"&gt;Finally, I would like to thank Adam Machanic (&lt;a target="_blank" href="http://sqlblog.com/blogs/adam_machanic"&gt;blog&lt;/a&gt; | &lt;a target="_blank" href="https://twitter.com/#!/AdamMachanic"&gt;twitter&lt;/a&gt;) for introducing me to the QUERYTRACEON syntax all that time ago, and Fabiano Amorim (&lt;a target="_blank" href="http://blogfabiano.com/"&gt;blog&lt;/a&gt; | &lt;a target="_blank" href="https://twitter.com/#!/mcflyamorim"&gt;twitter&lt;/a&gt;) for his email last year that kick-started the process of developing this presentation and blog series.&lt;/p&gt;  &lt;p align="left"&gt;Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx"&gt;Part 1&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-2.aspx"&gt;Part 2&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx"&gt;Part 3&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;© 2012 Paul White    &lt;br&gt;Twitter: &lt;a href="http://twitter.com/SQL_Kiwi"&gt;@SQL_Kiwi&lt;/a&gt;     &lt;br&gt;Email: &lt;a href="mailto:SQLkiwi@gmail.com"&gt;SQLkiwi@gmail.com&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Query Optimizer Deep Dive – Part 3</title><link>http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx</link><pubDate>Sun, 29 Apr 2012 07:30:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:43069</guid><dc:creator>Paul White</dc:creator><description>&lt;p&gt;This is the third part in a series of posts based on the content of the &lt;i&gt;Query Optimizer Deep Dive&lt;/i&gt; presentations I have given over the last month or so at the &lt;a target="_blank" href="http://www.aucklandsql.com"&gt;Auckland SQL Users’ Group&lt;/a&gt; and the SQL Saturday events in &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=136&amp;amp;sessionid=8411"&gt;Wellington, New Zealand&lt;/a&gt; and &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=139&amp;amp;sessionid=8412"&gt;Adelaide, Australia&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx"&gt;Part 1&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-2.aspx"&gt;Part 2&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/05/01/query-optimizer-deep-dive-part-4.aspx"&gt;Part 4&lt;/a&gt;&lt;/p&gt;  &lt;h3&gt;Storage of Alternative Plans&lt;/h3&gt;  &lt;p align="left"&gt;We saw in part 2 how optimizer rules are used to explore logical alternatives for parts of the query tree, and how implementation rules are used to find physical operations to perform each logical steps.&amp;nbsp; To keep track of all these options, the cost-based part of the SQL Server query optimizer uses a structure called the Memo.&amp;nbsp; This structure is part of the &lt;a target="_blank" href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.98.9460"&gt;Cascades&lt;/a&gt; general optimization framework developed by Goetz Graefe.&amp;nbsp; The Memo provides an efficient way to store many plan alternatives via the use of groups.&lt;/p&gt;  &lt;p align="left"&gt;Each group in the Memo initially contains just one entry – a node from the input logical tree.&amp;nbsp; As exploration and implementation phases progress, new groups may be added, and new physical and logical alternatives may be added to existing groups (all alternatives in a group share the same logical properties, but will often have quite different physical properties).&amp;nbsp; Groups are also shared between plan alternatives where possible, allowing Cascades to search more plans in the same time and space compared with other optimization frameworks.&lt;/p&gt;  &lt;p align="left"&gt;Continuing with our example query, the input tree to cost-based optimization is first copied into the Memo structure.&amp;nbsp; We can see this structure using trace flag 8608:&lt;/p&gt;  &lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:400px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;     &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; AdventureWorks2008R2;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; NOCOUNT &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;DBCC&lt;/span&gt; FREEPROCCACHE;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;DBCC&lt;/span&gt; TRACEON(3604);&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Initial memo contents&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Total = &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(inv.Quantity)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.ProductInventory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; inv &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    inv.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'[A-G]%'&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt; (QUERYTRACEON 8608);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;As a reminder, this is the logical input tree to cost-based optimization shown in part 2:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_2FEBE882.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Cost-Based Optimization Input Tree" border="0" alt="Cost-Based Optimization Input Tree" width="660" height="395" src="http://sqlblog.com/blogs/paul_white/image_thumb_73DFA6CC.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is copied to the Memo, one group per logical node, illustrated below:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_102CE8ED.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Optimizer Initial Memo Contents" border="0" alt="Optimizer Initial Memo Contents" width="660" height="280" src="http://sqlblog.com/blogs/paul_white/image_thumb_3254CEA6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The group numbers and linked structure shown are obtained directly from the trace flag output:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_5FA63EA9.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Trace Flag 8608 Output" border="0" alt="Trace Flag 8608 Output" width="321" height="572" src="http://sqlblog.com/blogs/paul_white/image_thumb_3244A8D9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;Each group has an entry number (all zero above since there is only one logical entry per group at this stage), with a logical operation (e.g. LogOp_Join), and the group numbers of any child groups (e.g. the logical join in group 13 references its two inputs, groups 8 and 9, and a logical comparison defined by the sub-tree starting at group 12).&lt;/p&gt;

&lt;h3&gt;Optimization Phases&lt;/h3&gt;

&lt;p align="left"&gt;One the initial Memo has been populated from the input tree, the optimizer runs up to four phases of search.&amp;nbsp; There is a documented DMV, &lt;a target="_blank" href="http://technet.microsoft.com/en-us/library/ms175002.aspx"&gt;sys.dm_exec_query_optimizer_info&lt;/a&gt;, that contains a number of counters specific to query optimization.&amp;nbsp; Four of these counters are ‘trivial plan’, search 0’, ‘search 1’, and ‘search 2’.&amp;nbsp; The value for each counter keeps track of the number of times a search phase was entered.&amp;nbsp; By recording the values before and after a specific optimization, we can see which phases were entered.&amp;nbsp; The current counter values on one of my test SQL Server instances is shown below, as an example:&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_1840C2EA.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="sys.dm_exec_query_optimizer_info" border="0" alt="sys.dm_exec_query_optimizer_info" width="265" height="129" src="http://sqlblog.com/blogs/paul_white/image_thumb_497F877D.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;We look at each of the four phases in a bit more detail next:&lt;/p&gt;

&lt;h4&gt;Search 0 – Transaction Processing&lt;/h4&gt;

&lt;p align="left"&gt;This phase is primarily concerned with finding good plans for OLTP-type queries, which usually join a number of tables using a navigational strategy (looking up a relatively small number of rows using an index).&amp;nbsp; This phase primarily considers nested-loops joins, though hash match may be used when a loops join implementation is not possible.&amp;nbsp; Many of the more advanced (and costly to explore) optimizer rules are not enabled during this search phase – for example search 0 never considers indexed view matching or parallel plans.&lt;/p&gt;

&lt;h4&gt;Search 1 – Quick Plan (also known as Complex Query I)&lt;/h4&gt;

&lt;p&gt;This search phase can use most or all of the available rules, can perform limited join reordering, and may be run a second time (to consider parallel plans only) if the first run produces a plan with a high enough cost.&amp;nbsp; Most queries find a final plan during one of the Search 1 runs.&lt;/p&gt;

&lt;h4&gt;Search 2 – Full Optimization&lt;/h4&gt;

&lt;p align="left"&gt;This phase uses the most comprehensive search configuration, and may result in significant compilation times in some cases.&amp;nbsp; The search is either for a serial or parallel plan, depending on which type was cheaper after search 1.&lt;/p&gt;

&lt;p align="left"&gt;The scripts accompanying this series show another way to see which phases were run, using trace flag 8675.&amp;nbsp; The output provides some extra insight into how things work (for example it shows the number of optimization moves (tasks) made in each stage).&amp;nbsp; The only documented and supported way to see the search phases is via the DMV, however.&lt;/p&gt;

&lt;h4 align="left"&gt;Entry and Termination Conditions&lt;/h4&gt;

&lt;p align="left"&gt;Each phase has entry conditions, a set of enabled rules, and termination conditions.&amp;nbsp; Entry conditions mean that a phase may be skipped altogether; for example, search 0 requires at least three joined tables in the input tree.&amp;nbsp; Termination conditions help to ensure the optimizer does not spend more time optimizing than it saves – if the current lowest plan cost drops below a configured value, the search will terminate early with a ‘Good Enough Plan Found’ result.&lt;/p&gt;

&lt;p align="left"&gt;The optimizer also sets a budget at the start of a phase for the number of optimization ‘moves’ it considers sufficient to find a pretty good plan (remember the optimizer’s goal is to find a good enough plan quickly).&amp;nbsp; If the process of exploring and implementing alternatives exceeds this ‘budget’ during a phase, the phase terminates with a ‘Time Out’ message.&amp;nbsp; Early termination (for whatever reason) is part of the optimizer’s design, completely normal, and not generally a cause for concern.&lt;/p&gt;

&lt;p align="left"&gt;From time to time, we might wish that the optimizer had different goals – perhaps that we could ask it to continue searching for longer – but this is not how it works.&amp;nbsp; It is all too easy to over-spend on optimization (finding transformations is not hard – finding ones that are robustly useful in a wide range of circumstances is), and full cost-based exploration is a memory and processor-intensive operation.&amp;nbsp; The optimizer contains many heuristics, checks and limits to avoid exploring unpromising alternatives, to prune the search space as it goes, and ultimately produce a pretty good plan pretty quickly, most of the time, on most hardware, in most databases.&lt;/p&gt;

&lt;h3&gt;Costing&lt;/h3&gt;

&lt;p align="left"&gt;First a quick summary: The optimizer runs up to four phases, each of which performs exploration using rules (finding new logical alternatives to some part of the tree), then a round of implementation rules (finding physical implementations for a logical part of the tree).&amp;nbsp; New logical or physical alternatives are added to the Memo structure – either as an alternative within an existing group, or as a completely new group.&amp;nbsp; Note that the Memo allows the optimizer to consider very many alternatives at once in a compact and quick-to-search structure; the optimizer does &lt;b&gt;not&lt;/b&gt; just work on one overall plan, performing incremental improvements (this is a common misconception).&lt;/p&gt;

&lt;p align="left"&gt;Having found all these alternatives, the optimizer needs a way to choose between them.&amp;nbsp; Costing runs after each round of implementation rules, producing a cost value for each physical alternative in each group in the memo (only physical operations can be costed, naturally).&amp;nbsp; Costing considers factors like cardinality, average row size, expected sequential and random I/O operations, processor time, buffer pool memory requirements, and the effect of parallel execution.&lt;/p&gt;

&lt;p align="left"&gt;Like many areas of optimization, the costing calculations are based on a complex mathematical model.&amp;nbsp; This model generally provides a good basis on which to compare alternatives internally, regardless of the workload or particular hardware configuration.&amp;nbsp; The costing numbers do not mean very much by themselves, so it is generally unwise to compare them between statements or across different queries.&amp;nbsp; The numbers are perhaps best thought of as a unit-less quantity, useful only when comparing alternative plans for the same statement.&lt;/p&gt;

&lt;p align="left"&gt;The model is just that of course: a model, albeit one that happens to produce very good results for most people most of the time.&amp;nbsp; The slide deck that accompanies this series contains details of some of the simplifying assumptions made in the model.&lt;/p&gt;

&lt;h3&gt;Final Memo Contents&lt;/h3&gt;

&lt;p align="left"&gt;At the end of each search phase, the Memo may have expanded to include new logical and physical alternatives for each group, perhaps some completely new groups.&amp;nbsp; We can see the contents after each phase using trace flag 8615:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Final memo&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Total = &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(inv.Quantity)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.ProductInventory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; inv &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    inv.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'[A-G]%'&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt; (RECOMPILE, QUERYTRACEON 8615);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;The final Memo (after each phase, remember) can be quite large, despite the techniques employed to constrain the search space.&amp;nbsp; Our simple test query only requires a single run through search 1, and terminates early after 509 moves (tasks) with a ‘Good Enough Plan Found’ message.&amp;nbsp; Despite that, the Memo contains 38 groups (up from 18) with many groups containing several alternatives.&amp;nbsp; The extract below highlights just the groups that relate directly to the join implementation:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_19E168F1.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Final Memo Trace Flag 8615 Contents" border="0" alt="Final Memo Trace Flag 8615 Contents" width="640" height="559" src="http://sqlblog.com/blogs/paul_white/image_thumb_5C908E5C.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;Looking at the green shaded areas, group 13 item 0 was the original (joining groups 8 and 9 and applying the condition described by the sub-tree starting with group 12).&amp;nbsp; It has gained an logical alternative (via the Join Commute rule, reversing the join input groups), and two surviving physical implementations: a one-to-many merge join as item 7, with group 8 option 2 as the first input, and group 9 option 2 as the second; and a physical inner Apply driven by group 8 option 6, on group 30 option 2.&amp;nbsp; Group 20 is completely new – another one-to-many merge join option, but this time with inputs from groups 19.4 and 8.2 with 12 familiar as the join condition.&amp;nbsp; Again, the scripts accompanying this series can be used to explore the details further, if you wish.&lt;/p&gt;

&lt;p align="left"&gt;The final selected plan consists of physical implementations chosen by starting with the lowest-cost physical option in the root group (18, shaded pink above).&amp;nbsp; The sub-tree from that point has a total estimated cost of 0.0295655 (this is the same cost shown in the final graphical execution plan).&amp;nbsp; The plan is produced by following the links in the Memo, from group 18 option 4, to group 20 option 6, and so on to the leaves:&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_18207750.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Good Enough Plan Found" border="0" alt="Good Enough Plan Found" width="289" height="209" src="http://sqlblog.com/blogs/paul_white/image_thumb_5B3BCFB0.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_778911D0.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Optimized Query Plan" border="0" alt="Optimized Query Plan" width="499" height="205" src="http://sqlblog.com/blogs/paul_white/image_thumb_657CCE43.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;End of Part 3&lt;/h4&gt;

&lt;p align="left"&gt;The original slides and demo code are attached below as a zip file.&lt;/p&gt;

&lt;p align="left"&gt;Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx"&gt;Part 1&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-2.aspx"&gt;Part 2&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/05/01/query-optimizer-deep-dive-part-4.aspx"&gt;Part 4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;© 2012 Paul White 
  &lt;br&gt;Twitter: &lt;a href="http://twitter.com/SQL_Kiwi"&gt;@SQL_Kiwi&lt;/a&gt; 

  &lt;br&gt;Email: &lt;a href="mailto:SQLkiwi@gmail.com"&gt;SQLkiwi@gmail.com&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Query Optimizer Deep Dive – Part 2</title><link>http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-2.aspx</link><pubDate>Sat, 28 Apr 2012 04:56:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:43049</guid><dc:creator>Paul White</dc:creator><description>&lt;p align="left"&gt;This is the second part in a series of posts based on the content of the &lt;i&gt;Query Optimizer Deep Dive&lt;/i&gt; presentations I have given over the last month or so at the &lt;a target="_blank" href="http://www.aucklandsql.com"&gt;Auckland SQL Users’ Group&lt;/a&gt; and the SQL Saturday events in &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=136&amp;amp;sessionid=8411"&gt;Wellington, New Zealand&lt;/a&gt; and &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=139&amp;amp;sessionid=8412"&gt;Adelaide, Australia&lt;/a&gt;.&lt;/p&gt;  &lt;p align="left"&gt;Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx"&gt;Part 1&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx"&gt;Part 3&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/05/01/query-optimizer-deep-dive-part-4.aspx"&gt;Part 4&lt;/a&gt;&lt;/p&gt;  &lt;h3 align="left"&gt;Cost-Based Optimization Overview&lt;/h3&gt;  &lt;p align="left"&gt;The input to cost-based optimization is a tree of logical operations produced by the previous optimization stages discussed in part one.&amp;nbsp; Cost-based optimization takes this logical tree, explores logical alternatives (different logical tree shapes that produce the same results), generates physical implementations, assigns an estimated cost to each, and finally chooses the cheapest physical option overall.&lt;/p&gt;  &lt;p align="left"&gt;The goal of cost-based optimization is &lt;i&gt;not&lt;/i&gt; to find the best possible physical execution plan by exploring every possible alternative; rather, the goal is to find a good plan quickly.&amp;nbsp; This approach gives us an optimizer that works pretty well for most workloads, most of the time.&amp;nbsp; If you think about it, that’s quite an achievement – after all, my database is likely very different from yours, and we probably run on quite different hardware as well.&amp;nbsp; The point about finding a good plan quickly is also important – generally, we would not want the optimizer to spend hours optimizing a query that runs for only a few seconds.&lt;/p&gt;  &lt;p align="left"&gt;This design has a number of important consequences.&amp;nbsp; First, a skilled query tuner will often be able to come up with a better plan than the optimizer does.&amp;nbsp; In some cases, this will because the human can reason about the query in a way the optimizer cannot.&amp;nbsp; Other times, it is simply a question of time – we might be happy spending half a day finding a great execution plan for a crucial query, whereas the optimizer places strict limits on itself to avoid spending more time on optimization than it saves on a single execution.&lt;/p&gt;  &lt;p align="left"&gt;Perhaps a future version of SQL Server will allow us to configure the optimizer to spend extra time on a particular query – today, we have to use query hints and ‘manual optimizations’ to encourage a particular execution plan shape.&amp;nbsp; The down side to circumventing the optimizer’s natural behaviour in this way is that we then have to take responsibility for ensuring that the execution plan remains good in the future, as data volumes and distributions change.&amp;nbsp; In most systems, it is best to limit the number of manually-tuned queries to a minimum, and thoroughly document any tricks you use to obtain a particular plan.&lt;/p&gt;  &lt;h3 align="left"&gt;Input Tree to Cost-Based Optimization&lt;/h3&gt;  &lt;p align="left"&gt;Back to the task at hand.&amp;nbsp; We have a sample query (reproduced below) that has been through all the previous optimization stages, did not qualify for a trivial plan, and so needs to go through the cost-based optimization process.&lt;/p&gt;  &lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;     &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Total = &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(inv.Quantity)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Production.ProductInventory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; inv&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    inv.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'[A-G]%'&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The tree of logical operations passed to the optimizer looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_4180456C.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Cost-Based Optimizer Input Tree" border="0" alt="Cost-Based Optimizer Input Tree" width="640" height="375" src="http://sqlblog.com/blogs/paul_white/image_thumb_5D31A4D7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;This looks very similar to the original logical tree seen in part one, though cardinality estimates have been added to each primary node, and the tree layout has been expanded a little into a form that is easier for the system to work with.&amp;nbsp; In addition to simple cardinality estimates, remember that each node also has statistics objects (histograms and frequency information) derived from the familiar statistics associated with the tables in the query.&lt;/p&gt;

&lt;p align="left"&gt;The tree above was built from information obtained using trace flag 3604 and 8606 (see part one for more details).&amp;nbsp; Trace flag 8606 shows the tree at various stages, the diagram above is built from the view after project normalization:&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_23323C1E.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Trace Flag 8606 Output" border="0" alt="Trace Flag 8606 Output" width="655" height="566" src="http://sqlblog.com/blogs/paul_white/image_thumb_154FD056.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Properties&lt;/h3&gt;

&lt;p align="left"&gt;There are also a number of other ‘properties’ associated with each node, that have been added by previous optimization stages.&amp;nbsp; These properties include logical attributes, such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;div align="left"&gt;Output columns and expressions&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Uniqueness (key) information&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Type information and nullability&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Functional dependencies&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Domain ranges for each column or expression&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p align="left"&gt;There are also some physical properties that may be present on each node, for example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;div align="left"&gt;Sort order at each node&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Partitioning information&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Halloween protection&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p align="left"&gt;The Halloween protection information is worth explaining in a bit more detail.&amp;nbsp; A query generally executes as a pipeline, with rows being requested one at a time from the top of the tree – so rows are in effect pulled up the tree one at a time.&amp;nbsp; This pipeline arrangement has a number of important advantages, but a problem can arise where the query modifies data: changes made by the query can affect rows being read by the same query – the classic example is a query that adds 10% to the salaries of every employee.&amp;nbsp; When processed as a pipeline, we can get stuck in an infinite loop as rows that have had 10% added re-qualify for reading.&amp;nbsp; This problem happened to be first discovered on 31 October 1976 and became known as the &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Halloween_Problem"&gt;Halloween Problem&lt;/a&gt;.&lt;/p&gt;

&lt;p align="left"&gt;One solution is to separate operations that read data from those that update data by reading all rows into temporary storage before performing any updates.&amp;nbsp; In SQL Server, this simple solution typically manifests as an Eager Table Spool in the query plan – all rows are written eagerly to temporary storage before any updates are performed.&amp;nbsp; This is a bit of a sledgehammer solution though, so the optimizer keeps track of which columns need protection from the Halloween problem (and how much protection they need) at each node by setting properties.&amp;nbsp; Some logical operations (like sorting) naturally mean that all input rows have to be read before the first output row can be produced.&amp;nbsp; These operations provide Halloween protection naturally, so an explicit Eager Table Spool would not be necessary.&amp;nbsp; There are a number of logical operations that can provide some degree of Halloween protection, and properties are used to ensure that just enough protection is provided, at minimum cost.&lt;/p&gt;

&lt;h3 align="left"&gt;Rules&lt;/h3&gt;

&lt;p align="left"&gt;The optimizer contains rules to transform trees.&amp;nbsp; There are four classes of rule:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;div align="left"&gt;Simplification&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Exploration&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Implementation&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Physical property enforcement&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simplification rules transform some part of the logical tree to a simpler logical form, and are responsible for the simplification transforms we saw in part one.&amp;nbsp; Exploration rules run only during cost-based optimization, generating new logical equivalents for some part of the existing logical tree.&amp;nbsp; Implementation rules produce a physical operation (like a hash or merge join) for a logical operation (a logical join).&amp;nbsp; Property enforcement rules introduce new elements to the logical tree to enforce some desired physical property at that point, for example to enforce a particular sorted order of rows (as might be required by a merge join or stream aggregate).&lt;/p&gt;

&lt;p align="left"&gt;There are 395 rules in SQL Serer 2012, most of which perform quite simple operations; it is the fact that many rules can be run in various orders that accounts for the apparent complexity of optimizer behaviour.&amp;nbsp; The way that simple rules can combine to produce complex behaviours reminds me of &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"&gt;Conway’s Game of Life&lt;/a&gt; – a cellular automation program with only four rules that nevertheless can produce extraordinarily complex and beautiful patterns as the rules are applied over and over.&lt;/p&gt;

&lt;h4 align="left"&gt;Exploration Rule Examples&lt;/h4&gt;

&lt;p align="left"&gt;One example of a simple exploration rule is SELonJN, a rule that merges a suitable relational SELECT (row filter) into a logical join operation:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_63B43CF3.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="SELonJN Exploration Rule" border="0" alt="SELonJN Exploration Rule" width="480" height="304" src="http://sqlblog.com/blogs/paul_white/image_thumb_0835A4AB.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another common exploration rule that generates a new logical alternative is JoinCommute:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_694F0AFF.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="JoinCommute Exploration Rule" border="0" alt="JoinCommute Exploration Rule" width="640" height="319" src="http://sqlblog.com/blogs/paul_white/image_thumb_71A2BA89.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;As the name suggests, JoinCommute explores a different logical join order, exploiting the fact that A JOIN B is equivalent to B JOIN A for inner joins.&amp;nbsp; Though logically equivalent, the different join orders may have different performance characteristics once the logical alternatives are translated to a physical implementation by a later implementation rule.&amp;nbsp; A third exploration rule that is relevant to our test query is GbAggBeforeJoin, a rule that explores the possibility of pushing an aggregation operation under a join:&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_0BD2FDE1.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="GbAggBeforeJoin Transformation" border="0" alt="GbAggBeforeJoin Transformation" width="480" height="486" src="http://sqlblog.com/blogs/paul_white/image_thumb_050FCE91.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4 align="left"&gt;Implementation Rule Examples&lt;/h4&gt;

&lt;p align="left"&gt;As mentioned previously, implementation rules transform part of a logical tree into a physical alternative:&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_61932A2B.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Optimizer Implementation Rules" border="0" alt="Optimizer Implementation Rules" width="640" height="263" src="http://sqlblog.com/blogs/paul_white/image_thumb_42405D8B.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;The diagram shows three join implementation rules, JNtoNL (nested loops), JNtoHS (hash join), JNtoSM (sort-merge join); two implementations for Group-By Aggregate, GbAggToStrm (Stream Aggregate) and GbAggToHS (Hash Aggregate); SelectToFilter, GetToScan, and GetIdxToRng.&lt;/p&gt;

&lt;h3&gt;Which Rules Were Used?&lt;/h3&gt;

&lt;p align="left"&gt;If we want to see which rules were used when optimizing a query, one option is to use an undocumented view which shows the number of times a rule has been asked to estimate how valuable it might be in the current context (its ‘promise’ value), the number of times the rule was used to generate an alternative section of the tree (‘built’), and the number of times the output of the rule was successfully incorporated into the search space (‘succeeded’).&amp;nbsp; A sample of the contents of the sys.dm_exec_query_transformation_stats DMV is shown below:&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_74940B3D.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="sys.dm_exec_query_transformation_stats" border="0" alt="sys.dm_exec_query_transformation_stats" width="640" height="305" src="http://sqlblog.com/blogs/paul_white/image_thumb_462A5FC3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;By taking a snapshot view of this information before and after optimizing a particular query, we can see which rules were run.&amp;nbsp; The DMV is instance-wide however, so you would need to run these tests on a system to which you have exclusive access.&amp;nbsp; The scripts that accompany this series of posts contain a complete test rig to show the rules used by each query.&lt;/p&gt;

&lt;h3 align="left"&gt;End of Part 2&lt;/h3&gt;

&lt;p align="left"&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx"&gt;Part three&lt;/a&gt; in this series covers the Memo structure and optimization phases in detail.&amp;nbsp; The original presentation slides and demo code are contained in the zip file shown below.&lt;/p&gt;

&lt;p align="left"&gt;Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx"&gt;Part 1&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx"&gt;Part 3&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/05/01/query-optimizer-deep-dive-part-4.aspx"&gt;Part 4&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;© 2012 Paul White 
  &lt;br&gt;Twitter: &lt;a href="http://twitter.com/SQL_Kiwi"&gt;@SQL_Kiwi&lt;/a&gt; 

  &lt;br&gt;Email: &lt;a href="mailto:SQLkiwi@gmail.com"&gt;SQLkiwi@gmail.com&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Query Optimizer Deep Dive - Part 1</title><link>http://sqlblog.com/blogs/paul_white/archive/2012/04/27/query-optimizer-deep-dive-part-1.aspx</link><pubDate>Fri, 27 Apr 2012 14:38:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:43025</guid><dc:creator>Paul White</dc:creator><description>&lt;p align="left"&gt;This is the first in a series of posts based on the content of the &lt;i&gt;Query Optimizer Deep Dive&lt;/i&gt; presentations I have given over the last month or so at the &lt;a target="_blank" href="http://www.aucklandsql.com"&gt;Auckland SQL Users’ Group&lt;/a&gt; and the SQL Saturday events in &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=136&amp;amp;sessionid=8411"&gt;Wellington, New Zealand&lt;/a&gt; and &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=139&amp;amp;sessionid=8412"&gt;Adelaide, Australia&lt;/a&gt;.&lt;/p&gt;  &lt;p align="left"&gt;Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-2.aspx"&gt;Part 2&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx"&gt;Part 3&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/05/01/query-optimizer-deep-dive-part-4.aspx"&gt;Part 4&lt;/a&gt;&lt;/p&gt;  &lt;h3 align="left"&gt;Introduction&lt;/h3&gt;  &lt;p align="left"&gt;The motivation behind writing these sessions is that I have found that relatively few people have a good intuition for the way the optimizer works, partly because the official documentation is rather sparse, and partly because what information is available is dispersed across many books and blog posts. The content presented here is very much geared to my preferred way of learning – it shows the concepts in what seems to me to be a reasonably logical sequence, and provides tools to enable the interested reader to explore further, if desired.&lt;/p&gt;  &lt;p align="left"&gt;When we write a query, we are &lt;i&gt;not&lt;/i&gt; writing a computer program that can be directly executed.&amp;nbsp; SQL is a declarative language used to logically describe the results we want to see.&amp;nbsp; SQL Server goes through a process of compilation and optimization to create a physically executable implementation of the stated logical requirement.&amp;nbsp; To put it another way, a SQL query is the &lt;i&gt;specification&lt;/i&gt; for an executable program that SQL Server writes for us.&amp;nbsp; The SQL Server component responsible for finding an efficient physical execution plan for a given logical query requirement is the Query Optimizer.&lt;/p&gt;  &lt;h3 align="left"&gt;The SQL Server Core Engine&lt;/h3&gt;  &lt;p align="left"&gt;The diagram below shows conceptually where the Query Optimizer sits in the core SQL Server engine:&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_4FBDD2B1.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="SQL Server Core Engine Diagram" border="0" alt="SQL Server Core Engine Diagram" width="640" height="265" src="http://sqlblog.com/blogs/paul_white/image_thumb_79DD5ACC.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;Language Processing is concerned with things like parsing the text of the query to make sure it is syntactically valid, binding table references to real database objects, deriving types for expressions, semantic analysis (for example checking that the query is not trying to execute a table), and binding GROUP BY references to the appropriate logical scope.&amp;nbsp; The Query Optimizer aims to find a good physical execution plan that matches the logical semantic of the query, and the Query Executor is responsible for running that plan to completion.&amp;nbsp; Below that, the Storage Engine provides access to physical storage, together with locking and transaction services.&amp;nbsp; Finally, SQL-OS is the layer that provides threading, memory management, and scheduling services.&lt;/p&gt;  &lt;p align="left"&gt;Using the same colours for the components shown above, a very high-level overview of query processing looks like this:&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_0F77936A.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Query Processing Overview" border="0" alt="Query Processing Overview" width="640" height="46" src="http://sqlblog.com/blogs/paul_white/image_thumb_7B11CDDE.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;This series of blog posts is mostly concerned with the “Optimize” step above.&amp;nbsp; It takes as its input a tree of logical operations produced by the previous stages.&lt;/p&gt;  &lt;h3 align="left"&gt;Optimization Pipeline&lt;/h3&gt;  &lt;p align="left"&gt;The diagram below shows the principal stages within query optimization, starting with the bound tree produced by the parser and algebrizer.&amp;nbsp; The coloured steps are the ones we will explore in depth – the right hand side of the diagram lists a bit more detail that I talk through when presenting this material live:&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_437C0CF0.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Query Optimization Pipeline" border="0" alt="Query Optimization Pipeline" width="640" height="433" src="http://sqlblog.com/blogs/paul_white/image_thumb_74BAD183.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h3 align="left"&gt;Input Tree&lt;/h3&gt;  &lt;p align="left"&gt;We start by looking at the bound logical tree (input tree).&amp;nbsp; To make the discussion a little less abstract, we will use a test query issued against the AdventureWorks sample database.&amp;nbsp; This simple query shows products and the quantity in stock, limited to products with names that start with a letter between A and G:&lt;/p&gt;  &lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;     &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Test query&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Total = &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(inv.Quantity)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Production.ProductInventory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; inv&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    inv.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'[A-G]%'&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The input tree generated by this query is shown below, slightly simplified:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_5C67B768.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Optimizer Logical Input Tree" border="0" alt="Optimizer Logical Input Tree" width="243" height="480" src="http://sqlblog.com/blogs/paul_white/image_thumb_193C393B.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;The operations in this tree are all purely logical, and have their roots in Relational Theory.&amp;nbsp; The GET operation logically reads an entire table, though you should not yet be thinking in terms of physical operations such as a scan or a seek.&amp;nbsp; The JOIN is a cartesian product, logically joining every row in one table with every row in the other.&amp;nbsp; The SELECT is not a SQL statement, it is a relational operation: filtering rows based on some condition (known as a predicate).&amp;nbsp; Here, we are applying two SELECT operations to filter on matching product IDs and rows where the product name starts with a letter between A and G.&amp;nbsp; The next logical operation is a Group-By Aggregate, an extension to the basic relational algebra that logically groups rows by some common attribute, and optionally computes an aggregate expression for each group.&amp;nbsp; Finally, we have a relational Project operation, which filters columns – here we only need the Name and Total columns, and those are the only two returned in the logical result set.&lt;/p&gt;

&lt;p align="left"&gt;To see this tree directly, we can use undocumented trace flag 8605.&amp;nbsp; This flag also requires the common trace flag 3604 to produce output to the SSMS messages window.&amp;nbsp; We can use another undocumented syntax, the QUERYTRACEON hint, to set the trace flag just for this query:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Input tree (ISO-92)&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Total = &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(inv.Quantity)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.ProductInventory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; inv &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    inv.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'[A-G]%'&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt; (RECOMPILE, QUERYTRACEON 8605);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;Now, in the SSMS messages tab, we see a textual representation of the tree of logical operators I drew with coloured boxes before:&lt;/p&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_03FE0DC6.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Trace Flag 8605 Output" border="0" alt="Trace Flag 8605 Output" width="660" height="626" src="http://sqlblog.com/blogs/paul_white/image_thumb_680CD8CD.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;There are a few minor differences between this and the previous diagram.&amp;nbsp; In particular, the expression computed by the aggregate is added by a separate projection (omitted for clarity before), and the SQL-92 join syntax means the join predicate is more tightly bound to the logical join.&amp;nbsp; Rewriting the query using SQL-89 syntax highlights the second difference, producing a tree closer to the cartesian product followed by a relational SELECT:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Input tree (ISO-89)&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Total = &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(inv.Quantity)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    Production.ProductInventory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; inv&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    inv.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'[A-G]%'&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt; (RECOMPILE, QUERYTRACEON 8605);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;&lt;a href="http://sqlblog.com/blogs/paul_white/image_4C1BA3D5.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="Input Tree SQL-89 Syntax" border="0" alt="Input Tree SQL-89 Syntax" width="644" height="670" src="http://sqlblog.com/blogs/paul_white/image_thumb_3434BCAF.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 align="left"&gt;Simplification&lt;/h3&gt;

&lt;p align="left"&gt;The first step of the optimization pipeline we will look at is simplification, where the optimizer looks to rewrite parts of the logical tree to remove redundancies and move logical operations around a bit to help later stages.&amp;nbsp; Major activities that occur around the time simplification occurs (I have taken a little artistic licence here to group a few separate stages together) include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;div align="left"&gt;Constant folding&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Domain simplification&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Predicate push-down&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;Join simplification &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;Contradiction detection&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p align="left"&gt;Constant folding is the process of evaluating an expression during optimization, rather than repeatedly at execution time.&amp;nbsp; In the following example, the complex expression in the WHERE clause can safely be evaluated early, resulting in “WHERE p.Name LIKE ‘D%’:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; p.Name&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;SUBSTRING&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;LEFT&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;CHAR&lt;/span&gt;(ASCII(&lt;span style="color:#0000ff;"&gt;CHAR&lt;/span&gt;(68))), 1) + &lt;span style="color:#006080;"&gt;'%'&lt;/span&gt;, 1, 2);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;Domain simplification enables the optimizer to reason about the range of valid values a column or expression can take.&amp;nbsp; In the next query, the only value for Product ID that logically matches all the predicates in the extended WHERE clause is the single value ‘400’.&amp;nbsp; The query plan shows that simplification has reduced the three predicates to a single equality predicate, “WHERE p.ProductID = 400”:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt; (10) * &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; p.ProductID &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 300 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 400&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; p.ProductID &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 200 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 500&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; p.ProductID &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 400 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 600;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;Predicate push-down involves pushing relational SELECTs (logically filtering rows based on a predicate) down the logical tree toward the leaves.&amp;nbsp; The heuristic here is that this is always a good thing to do (at least as far as expressions that reference a column are concerned) because it eliminates rows early, reducing the number for later logical operations.&amp;nbsp; Moving SELECTs closer to the logical GETs (reading tables) also helps index and computed-column matching.&lt;/p&gt;

&lt;p align="left"&gt;Join simplification allows the optimizer to remove unnecessary joins, convert logical outer joins to simpler inner joins where the NULLs introduces by the outer join are later rejected by another feature in the query, and remove provably empty subexpressions.&amp;nbsp; This is an incredibly powerful optimizer facility, with its roots again in relational theory.&amp;nbsp; Rob Farley has written (&lt;a target="_blank" href="http://www.amazon.com/SQL-Server-MVP-Deep-Dives/dp/1935182048"&gt;SQL Server MVP Deep Dives&lt;/a&gt;) and presented (&lt;a title="http://bit.ly/SimpleRob" href="http://bit.ly/SimpleRob"&gt;http://bit.ly/SimpleRob&lt;/a&gt;) about ways to use this feature effectively.&amp;nbsp; In particular, he talks about how to write views to benefit from compile-time simplification, and avoid the views-on-views-on-views problem.&amp;nbsp; The following queries illustrate some of the join simplifications:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Remove unnecessary joins&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    th.ProductID,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(th.ActualCost)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.TransactionHistory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; th&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.ProductID = th.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    th.ProductID;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Outer join to join (null rejection)&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; * &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;LEFT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.TransactionHistory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; th &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    th.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; th.ProductID &amp;lt; 10;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Complex example combining multiple simplifications&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; Complex &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;(&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        pc.ProductCategoryID, pc.Name &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; CatName,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        ps.ProductSubcategoryID, ps.Name &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; SubCatName,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        p.ProductID, p.Name &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; ProductName,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        p.Color, p.ListPrice, p.ReorderPoint,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        pm.Name &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; ModelName, pm.ModifiedDate&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.ProductCategory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; pc&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;FULL&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.ProductSubcategory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; ps &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        ps.ProductCategoryID = pc.ProductCategoryID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;FULL&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        p.ProductSubcategoryID = ps.ProductSubcategoryID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;FULL&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Production.ProductModel &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; pm &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        pm.ProductModelID = p.ProductModelID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; c.ProductID, c.ProductName&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Complex &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; c&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; c.ProductName &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'G%'&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;That last example, with three full outer joins in a CTE (in-line view), simplifies down to a simple index seek on one table.&lt;/p&gt;

&lt;h3 align="left"&gt;Cardinality Estimation&lt;/h3&gt;

&lt;p align="left"&gt;The optimizer only has direct information about table cardinality (total number of rows) for base tables.&amp;nbsp; Statistics can provide additional histograms and frequency statistics, but again these are only maintained for base tables.&amp;nbsp; To help the optimizer choose between competing strategies later on, it is essential to know how many rows are expected at each node in the logical tree, not just at the GET leaf nodes.&amp;nbsp; In addition, cardinality estimates above the leaves can be used to choose an initial join order (assuming the query contains several joins).&lt;/p&gt;

&lt;p align="left"&gt;Cardinality estimation computes expected cardinality and distribution statistics for each node, working up from the leaves one node at a time.&amp;nbsp; The logic used to create these derived estimates and statistics uses a model that makes certain assumptions about your data.&amp;nbsp; For example, where the distribution of values is unknown, it is assumed to be uniform across the whole range of potential values.&lt;/p&gt;

&lt;p align="left"&gt;You will generally get more accurate cardinality estimates if your queries fit the model used, and, as with many things in the wider optimizer, simple and relational is best.&amp;nbsp; Complex expressions, unusual or novel techniques, and using non-relational features often means cardinality estimation has to resort to guessing.&lt;/p&gt;

&lt;p align="left"&gt;Most of the choices made by the optimizer are driven by cardinality estimation, so if these are wrong, any good execution plans you might see are highly likely to be down to pure luck.&lt;/p&gt;

&lt;h3 align="left"&gt;Trivial Plan&lt;/h3&gt;

&lt;p align="left"&gt;The next stage of the optimizer pipeline is Trivial Plan, which is a fast path to avoid the time and effort involved in full cost-based optimization, and only applies to logical query trees that have a clear and obvious ‘best’ execution plan.&amp;nbsp; The details of which types of query can benefit from Trivial Plan change frequently, but things like joins, subqueries, and inequality predicates generally prevent this optimization.&amp;nbsp; The queries below show some examples where Trivial Plan can, and cannot be applied:&lt;/p&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Trivial plan&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; p.Name = N&lt;span style="color:#006080;"&gt;'Blade'&lt;/span&gt;;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Still trivial&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    RowNumber =&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;        ROW_NUMBER() &lt;span style="color:#0000ff;"&gt;OVER&lt;/span&gt; (&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;            &lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; p.Name)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; p.Name &lt;span style="color:#0000ff;"&gt;LIKE&lt;/span&gt; N&lt;span style="color:#006080;"&gt;'[A-G]%'&lt;/span&gt;;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- 'Subquery' prevents a trivial plan&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; p.ProductID)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; p.Name = N&lt;span style="color:#006080;"&gt;'Blade'&lt;/span&gt;;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;-- Inequality&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; p.Name &amp;lt;&amp;gt; N&lt;span style="color:#006080;"&gt;'Blade'&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p align="left"&gt;One interesting case where a Trivial Plan is not applied is where the estimated cost of the Trivial Plan query exceeds the configured ‘cost threshold for parallelism’.&amp;nbsp; The reasoning here is that any trivial plan that would qualify for a parallel plan suddenly presents a choice, and a choice means the query is no longer ‘trivial’, and we have to go through full cost-based optimization.&amp;nbsp; Taking this to the extreme, a SQL Server instance with the parallelism cost threshold set to zero will never produce a trivial plan (since all queries have a cost greater than zero).&amp;nbsp; At the risk of stating the slightly obvious, note that a plan produced at this stage will always be serial.&amp;nbsp; For experimentation only, the trivial plan stage can also be disabled using trace flag 8757.&lt;/p&gt;

&lt;p align="left"&gt;You can check whether a query used a trivial plan or not by inspecting the Properties window in SSMS, and clicking on the root node of the graphical query plan.&amp;nbsp; The ‘optimization level’ property will show ‘Trivial’ or ‘Full’ – the latter shows that a trip through full cost-based optimization was required.&amp;nbsp; If a query results in a trivial plan, a physical execution plan is produced and the optimization process ends here.&lt;/p&gt;

&lt;h3 align="left"&gt;End of Part 1&lt;/h3&gt;

&lt;p align="left"&gt;The original slides and demo code are contained in the zip file attached below.&amp;nbsp; Links to other parts of this series: &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-2.aspx"&gt;Part 2&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/04/29/query-optimizer-deep-dive-part-3.aspx"&gt;Part 3&lt;/a&gt; &lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2012/05/01/query-optimizer-deep-dive-part-4.aspx"&gt;Part 4&lt;/a&gt;&lt;/p&gt;

&lt;p align="left"&gt;© 2012 Paul White 
  &lt;br&gt;Twitter: &lt;a href="http://twitter.com/SQL_Kiwi"&gt;@SQL_Kiwi&lt;/a&gt; 

  &lt;br&gt;Email: &lt;a href="mailto:SQLkiwi@gmail.com"&gt;SQLkiwi@gmail.com&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Upgrading to SQL Server 2012 with Lock Pages in Memory</title><link>http://sqlblog.com/blogs/aaron_bertrand/archive/2012/02/06/upgrading-to-sql-server-2012-with-lock-pages-in-memory.aspx</link><pubDate>Mon, 06 Feb 2012 20:36:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:40107</guid><dc:creator>AaronBertrand</dc:creator><description>&lt;p&gt;During SQL Server 2012 RC0 setup (specifically when upgrading), you may have noticed upgrade rules regarding Lock Pages in Memory (LPIM):&lt;/p&gt;

&lt;p style="margin-left:40px;"&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2011/12/lpim_9.png" height="615" border="0" width="820"&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;However, for most folks, these rules always pass, whether or not they are actually using LPIM. I wanted to run a few tests to demonstrate why this is - or at least in which situations the rule checks will fail. So I created two virtual machines running SQL Server 2008 R2 SP1 CU3 - one running Windows Server 2008 SP2 (x86), the other running Windows Server 2008 R2 SP1 (x64 obviously). Both machines have 4 CPUs and 8GB of RAM, and have been updated with all Windows Updates (except Internet Explorer) as of the time of writing. I set up SQL Server to run as an explicit user account (to make it easy to assign LPIM rights for the appropriate tests). &lt;/p&gt;

&lt;p&gt;I will attempt to upgrade SQL Server under various scenarios (LPIM / AWE on x86, and LPIM / trace flag 845 on x64 - &lt;a href="http://support.microsoft.com/kb/970070" title="http://support.microsoft.com/kb/970070" target="_blank"&gt;required for LPIM on Standard Edition&lt;/a&gt;). All of these tests will be run with LPIM enabled, but other settings will vary as follows:&lt;br&gt;&lt;/p&gt;
&lt;div style="margin-left:40px;"&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2011/12/lpim_7a.png" height="109" border="0" width="597"&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;On the 2008 box, to make sure that AWE can be used by SQL Server, you may first need to set this at the operating system level - this depends on the specific operating system, whether DEP is enabled, amount of RAM and other factors. It used to be quite easy - go into boot.ini, add the /PAE switch, and reboot. Starting with Windows Server 2008, this changed to use the command-line utility bcdedit. To ensure that AWE and PAE are explicitly set on this specific system (x86 box with 8GB RAM), you could run the following command at an elevated command prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;bcdedit /set pae ForceEnable&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;


&lt;p&gt;Of course we don't have to do any of this on the x64 box - and in my case I didn't need to do this on the x86 box, either. But the matrix for the above can become quite complicated, and is just one more reason to get off of x86 - both Windows and SQL Server - as soon as you can! (Never mind that AWE is no longer supported in SQL Server 2012, nor is a cluster on WoW.)&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Next, to set Lock Pages in Memory, we need to launch the Local Group Policy Editor (Start &amp;gt; Run &amp;gt; gpedit.msc) and add the SQL Server service account to Computer Configuration &amp;gt; Windows Settings &amp;gt; Security Settings &amp;gt; Local Policies &amp;gt; User Rights Assignment &amp;gt; Lock pages in memory:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2011/12/lpim_1.png" height="404" border="0" width="688"&gt;&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then set SQL Server to run as the matching account so that it inherits the LPIM rights. You can always change this later, but for a one-off test like this it can be just as easy to specify the service account during setup:&lt;/p&gt;

&lt;p style="margin-left:40px;"&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2011/12/lpim_2.png" height="448" border="0" width="739"&gt; &lt;br&gt;&lt;/p&gt;

&lt;p&gt;We can then enable trace flag 845 using SQL Server Configuration Manager - right click the appropriate service, choose Properties, and on the Advanced tab, add -T845 to the Startup Parameters list (make sure there is no space between the last ; and -T845):&lt;/p&gt;

&lt;p style="margin-left:40px;"&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2011/12/lpim_3.png" height="579" border="0" width="728"&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Note that this is much easier with SQL Server 2012 client tools installed, even against older versions of SQL Server, as there is a new Startup Parameters tab to help you avoid messy typing inside that little combo box:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_startup.png" height="498" width="428"&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And finally, to enable SQL Server to utilize AWE on the x86 box, you can use the UI through Management Studio, or you can run the following code using sp_configure:&lt;/p&gt;

&lt;blockquote&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="blue"&gt;EXEC &lt;/font&gt;&lt;font color="darkred"&gt;sp_configure &lt;/font&gt;&lt;font color="red"&gt;'show advanced options'&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;1&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;RECONFIGURE WITH OVERRIDE&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;GO&lt;/font&gt;&lt;br&gt;&lt;font color="blue"&gt;&lt;br&gt;EXEC &lt;/font&gt;&lt;font color="darkred"&gt;sp_configure &lt;/font&gt;&lt;font color="red"&gt;'awe enabled'&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;1&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;RECONFIGURE WITH &lt;/font&gt;&lt;font color="blue"&gt;OVERRIDE&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;GO&lt;/font&gt;&lt;br&gt;&lt;br&gt;&lt;font color="blue"&gt;EXEC &lt;/font&gt;&lt;font color="darkred"&gt;sp_configure &lt;/font&gt;&lt;font color="red"&gt;'show advanced options'&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;0&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;RECONFIGURE WITH &lt;/font&gt;&lt;font color="blue"&gt;OVERRIDE&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;GO&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;


&lt;p&gt;(This is all just for testing purposes, but of course I need to point out that you wouldn't just enable AWE or LPIM without also adjusting min/max server memory appropriately and without proper consideration into what other services on the box will need memory.) &lt;br&gt;&lt;/p&gt;

&lt;p&gt;Restart each box and we should be ready for the first tests. We can verify LPIM / AWE via the following entries the SQL Server error log after restart:&lt;/p&gt;

&lt;p style="margin-left:40px;"&gt;For x64, there will be a line item that says "Using locked pages for buffer pool.":&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x64_log.png" height="96" border="1" width="435"&gt;&lt;br&gt;&lt;/p&gt;

&lt;p style="margin-left:80px;"&gt;When LPIM is not enabled (e.g. when the user rights assignment has not been set or the trace flag is not in use), the line above does not appear.&lt;/p&gt;

&lt;p style="margin-left:40px;"&gt;For x86, a message like "Using locked pages for buffer 
pool." will not appear in the error log, even though LPIM is enabled in 
this case. Instead you will see a line item about AWE, "Address Windowing Extensions is enabled": &lt;/p&gt;

&lt;p style="margin-left:40px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x86_log1.png" height="96" border="1" width="567"&gt;&lt;br&gt;&lt;/p&gt;
&lt;div style="margin-left:80px;"&gt;On
 x86 if LPIM is not enabled (e.g. if you haven't used the trace flag on 
Standard Edition, have not enabled AWE, or have not set the user rights correctly), you will see 
different error messages in the log, such as "SQL Server is not configured to use all of the available system memory. To enable SQL Server to use more memory, set the awe enabled option to 1 by using the sp_configure stored procedure." and "Addressing Windowing Extensions (AWE) requires the 'lock pages in memory' privilege which is not currently present in the access token of the process.":&lt;br&gt;&lt;/div&gt;&lt;div style="margin-left:80px;"&gt;&amp;nbsp;&lt;/div&gt;&lt;div style="margin-left:80px;"&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x86_log3.png" height="152" border="1" width="770"&gt;&amp;nbsp;&lt;/div&gt;

&lt;p&gt;One issue you might come across is the case where you've triple-checked everything - you know you've given the service account LPIM rights in the Group Policy editor, you've set the trace flag and you've restarted SQL Server, but the error log still seems to indicate that LPIM is not set. Please verify that you've entered the trace flag argument correctly. The following two entries are not the same, and only the first is valid:&lt;/p&gt;

&lt;blockquote&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;...\mastlog.ldf;-T845;&lt;br&gt; &lt;br&gt;...\mastlog.ldf; -T845;&lt;br&gt;&lt;font color="green"&gt;----------------^  this space may make you scream&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;


&lt;p&gt;Once you've verified that LPIM is up and running, let's go through the first few steps of SQL Server 2012 RC0 setup and see how the rule checks pan out. &lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;font size="4"&gt;32-bit systems&lt;/font&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;b&gt;AWE and trace flag 845 both enabled&lt;/b&gt;&lt;br&gt;&lt;br&gt;If you have AWE enabled and the trace flag turned on, the AWE check fails:&lt;br&gt;&lt;br&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x86_check1.png" height="203" border="1" width="416"&gt;&amp;nbsp;


&lt;blockquote style="margin-left:0px;"&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;---------------------------&lt;br&gt;Rule Check Result&lt;br&gt;---------------------------&lt;br&gt;Rule "Is AWE Enabled Check for x86 installations" failed.&lt;br&gt;&lt;br&gt;AWE is currently enabled on a 32-bit instance of SQL Server. This feature is no longer supported. &lt;br&gt;You must disable AWE before upgrading the instance.&lt;br&gt;---------------------------&lt;br&gt;OK&amp;nbsp;&amp;nbsp; &lt;br&gt;---------------------------&lt;br&gt;
&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;/li&gt;

&lt;li&gt; &lt;b&gt;AWE disabled, trace flag 845 enabled&lt;/b&gt;&lt;br&gt;&lt;br&gt;If you disable AWE and restart the service, you will see the above message about using sp_configure in the error log, but both the AWE and the LPIM checks pass. This is because you didn't already have LPIM enabled, since AWE was not enabled. Even though you might have thought that you were using LPIM prior to the upgrade:


&lt;p&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x86_check2.png" height="225" border="1" width="416"&gt;&amp;nbsp;&lt;/p&gt;

&lt;blockquote style="margin-left:0px;"&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;---------------------------&lt;br&gt;Rule Check Result&lt;br&gt;---------------------------&lt;br&gt;Rule "LPIM Check for x86 installations" passed.&lt;br&gt;&lt;br&gt;Lock Pages In Memory (LPIM) check for X86 succeeded.&lt;br&gt;---------------------------&lt;br&gt;OK&amp;nbsp;&amp;nbsp; &lt;br&gt;---------------------------
&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;/li&gt;

&lt;li&gt;&lt;b&gt;AWE enabled, trace flag 845 disabled&lt;/b&gt;&lt;br&gt;&lt;br&gt; If you re-enable AWE and then turn off the 845 trace flag, you won't see any error messages in the error log, except for the "AWE is enabled" message. And you will see the same AWE rule fail upgrade you'll see if you have the trace flag turned on:&amp;nbsp;

&lt;p&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x86_check1.png" height="203" border="1" width="416"&gt;&lt;/p&gt;

&lt;blockquote style="margin-left:0px;"&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;---------------------------&lt;br&gt;
Rule Check Result&lt;br&gt;
---------------------------&lt;br&gt;
Rule "Is AWE Enabled Check for x86 installations" failed.&lt;br&gt;
&lt;br&gt;
AWE
 is currently enabled on a 32-bit instance of SQL Server. This feature 
is no longer supported. &lt;br&gt;You must disable AWE before upgrading the 
instance.&lt;br&gt;
---------------------------&lt;br&gt;
OK&amp;nbsp;&amp;nbsp; &lt;br&gt;
---------------------------
&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;/li&gt;

&lt;li&gt; &lt;b&gt;AWE and trace flag 845 both disabled&lt;/b&gt;&lt;br&gt;&lt;br&gt;If you then disable AWE and leave the trace flag disabled, you get the message in the log about not using all of the available memory, but again, like in case 2., both the AWE and LPIM upgrade rule checks pass:


&lt;p&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x86_check2.png" height="225" border="1" width="416"&gt;&amp;nbsp;&lt;/p&gt;

&lt;blockquote style="margin-left:0px;"&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;---------------------------&lt;br&gt;
Rule Check Result&lt;br&gt;
---------------------------&lt;br&gt;
Rule "LPIM Check for x86 installations" passed.&lt;br&gt;
&lt;br&gt;
Lock Pages In Memory (LPIM) check for X86 succeeded.&lt;br&gt;
---------------------------&lt;br&gt;
OK&amp;nbsp;&amp;nbsp; &lt;br&gt;
---------------------------
&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;So for x86, I found no way to trigger an upgrade rule failure for the specific "LPIM Check for x86 installations" using RC0, but perhaps by RTM, this rule will also fail in addition to the AWE check in cases 1. and 3. above. In any case, I don't think it's that big of a deal since, if you are running x86, you won't be able to take advantage of AWE or LPIM anyway (more on that below). I think during the upgrade process you should be warned about this on any x86 machine with more than 4GB of RAM, regardless of your current AWE settings or trace flags. Not everyone is going to read the &lt;a href="http://technet.microsoft.com/en-us/library/ms144262%28SQL.110%29.aspx" title="http://technet.microsoft.com/en-us/library/ms144262%28SQL.110%29.aspx" target="_blank"&gt;discontinued engine features topic&lt;/a&gt; or attend one of my "What's New in SQL Server 2012?" presentations, and they may not realize later that when they change those settings they are not going to have any effect.&lt;/p&gt;

&lt;p&gt;Note that in SQL Server 2012, AWE is no longer supported. So it may very
 well be the case that you were expecting your AWE settings (in 
sp_configure, not in boot.ini) and LPIM to play well together after 
upgrading to SQL Server 2012, but this is not the case - SQL Server will
 no longer be able to see all of your memory, and this may have 
significant impact on your workload. Of course if you have a machine 
with 16GB of RAM and suddenly SQL Server will only see about 4GB, you 
might not be too impressed with the "upgrade" - hence the warnings. Note
 also that your experience with the RCs of SQL Server 2012 (all of which
 are Evaluation Edition) may yield different results than what will 
happen at RTM time (when you will be able to use a license key to 
specify "normal" editions like Standard and perform an actual end-to-end
 upgrade).&lt;br&gt; &lt;br&gt;&lt;/p&gt;
&lt;font size="4"&gt;
64-bit systems&lt;/font&gt;&lt;br&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Trace flag 845 enabled&lt;/b&gt;&lt;br&gt;&lt;br&gt;As expected, with both LPIM and TF845 enabled, the upgrade rule "LPIM Check for x64 Installations" passes (even though the "Using locked pages in memory" message does not appear in the error log). There is nothing to warn the user about because LPIM will continue to be honored:&lt;br&gt;&lt;br&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x64_check2.png" height="203" border="1" width="416"&gt;


&lt;blockquote style="margin-left:0px;"&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;---------------------------&lt;br&gt;
Rule Check Result&lt;br&gt;
---------------------------&lt;br&gt;
Rule "LPIM Check for x64 installations" passed.&lt;br&gt;
&lt;br&gt;
Lock Pages In Memory (LPIM) check for X64 succeeded.&lt;br&gt;
---------------------------&lt;br&gt;
OK&amp;nbsp;&amp;nbsp; &lt;br&gt;
---------------------------
&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;/li&gt;

&lt;li&gt;&lt;b&gt;Trace flag 845 disabled&lt;/b&gt;&lt;br&gt;&lt;br&gt;If we restart SQL Server without the trace flag, we no longer see the "Using locked pages for buffer pool" message in the error log, but the LPIM check still succeeds - even though we're on Standard Edition and the trace flag is not set (which is the reason behind the warning):&lt;br&gt;&lt;br&gt;&lt;img src="http://bertrandaaron.files.wordpress.com/2012/02/lpim_x64_check2.png" height="203" border="1" width="416"&gt;

&lt;blockquote style="margin-left:0px;"&gt;
&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div style="padding:10px 20px;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;---------------------------&lt;br&gt;Rule Check Result&lt;br&gt;---------------------------&lt;br&gt;Rule "LPIM Check for x64 installations" passed.&lt;br&gt;&lt;br&gt;Lock Pages In Memory (LPIM) check for X64 succeeded.&lt;br&gt;---------------------------&lt;br&gt;OK&amp;nbsp;&amp;nbsp; &lt;br&gt;---------------------------
&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

This last case is the most concerning to me. The point of the warning is to let me know that I have the LPIM permission set for the service account, but that it won't be honored without the trace flag because I'm running Standard Edition. In this specific case, I think the LPIM upgrade rule should fail, even though my current configuration also prevents me from using LPIM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br&gt;&lt;font size="4"&gt;Conclusion&lt;/font&gt; &lt;br&gt;&lt;/p&gt;


&lt;p&gt;I quite sincerely hope this is my last 32-bit related blog post. For one, the x86 installation of SQL Server took at least five times longer than the x64 equivalent. x86 RIP!&lt;/p&gt;

&lt;p&gt;In any case, this is just one way Microsoft is helping to prevent customers from shooting off their own feet. Especially in the x86 case where their current workloads are dependent upon AWE; it needs to be clear to them that after the upgrade to SQL Server 2012, their configuration isn't what they think it is... &lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;/p&gt;</description></item><item><title>How to Find the Statistics Used to Compile an Execution Plan</title><link>http://sqlblog.com/blogs/paul_white/archive/2011/09/20/how-to-find-the-statistics-used-to-compile-an-execution-plan.aspx</link><pubDate>Tue, 20 Sep 2011 15:22:15 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:38595</guid><dc:creator>Paul White</dc:creator><description>&lt;p&gt;In this post, I show you how to determine exactly which statistics objects were used by the query optimizer to produce an execution plan.&lt;/p&gt;  &lt;h3&gt;Trace Flags&lt;/h3&gt;  &lt;p&gt;We will need three undocumented trace flags.&amp;#160; The first one (&lt;strong&gt;3604&lt;/strong&gt;) is well-known – it redirects trace output to the client so it appears in the SSMS messages tab.&lt;/p&gt;  &lt;p&gt;The second trace flag is &lt;strong&gt;9292&lt;/strong&gt;.&amp;#160; With this enabled, we get a report of statistics objects which are considered ‘interesting’ by the query optimizer when compiling, or recompiling the query in question.&amp;#160; For potentially useful statistics, just the header is loaded.&lt;/p&gt;  &lt;p&gt;The third trace flag is &lt;strong&gt;9204&lt;/strong&gt;.&amp;#160; With this enabled, we see the ‘interesting’ statistics which end up being fully loaded and used to produce cardinality and distribution estimates for some plan alternative or other.&amp;#160; Again, this only happens when a plan is compiled or recompiled – not when a plan is retrieved from cache.&lt;/p&gt;  &lt;p&gt;You can enable and disable these flags with the usual DBCC TRACEON and TRACEOFF commands, but it is also possible to enable them just for a particular statement using the undocumented QUERYTRACEON query hint (demonstrated below).&lt;/p&gt;  &lt;h3&gt;Sample Query&lt;/h3&gt;  &lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:400px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;     &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;DBCC&lt;/span&gt; FREEPROCCACHE&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    total_quantity = &lt;span style="color:#0000ff;"&gt;SUM&lt;/span&gt;(th.Quantity)&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; AdventureWorks.Production.Product &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; p&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; AdventureWorks.Production.TransactionHistory &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; th &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    th.ProductID = p.ProductID&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    th.ActualCost &amp;gt;= $5.00&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; p.Color = N&lt;span style="color:#006080;"&gt;'Red'&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;GROUP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    p.Name&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;OPTION&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;(&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    QUERYTRACEON 3604,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    QUERYTRACEON 9292,&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    QUERYTRACEON 9204&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The DBCC FREEPROCCACHE is just there to empty the plan cache so we get a compilation.&amp;#160; You can also evict the current plan from cache if you know its handle (SQL Server 2008) or use a RECOMPILE query hint.&amp;#160; Using RECOMPILE is often convenient, but you may get a different plan compared to that obtained without the hint.&amp;#160; Note that compiling the query is enough – we do not need to execute the query; simply requesting an ‘estimated plan’ will do.&amp;#160; It doesn’t hurt to run it either though, just to be clear.&lt;/p&gt;

&lt;h3&gt;Sample Output&lt;/h3&gt;

&lt;div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:'Courier New', courier, monospace;direction:ltr;max-height:500px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;padding-top:4px;" id="codeSnippetWrapper"&gt;
  &lt;div style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;
    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats header loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.Product, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 1, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: ProductID, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.Product, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 1, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: ProductID, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats header loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.Product, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 3, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: Name, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.Product, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 3, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: Name, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats header loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.Product, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 11, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: Color, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.Product, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 11, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: Color, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats header loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.TransactionHistory, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 2, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: ProductID, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.TransactionHistory, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 2, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: ProductID, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats header loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.TransactionHistory, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 5, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: ActualCost, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;Stats loaded: &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    DbName: AdventureWorks, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ObjName: AdventureWorks.Production.TransactionHistory, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    IndexId: 5, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    ColumnName: ActualCost, &lt;/pre&gt;


    &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:white;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:'Courier New', courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;"&gt;    EmptyTable: &lt;span style="color:#0000ff;"&gt;FALSE&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;There’s no sign of an official way to get this very useful information in Denali, despite it being requested many times over the years.&amp;#160; Trace flag 9204 works at least as far back as SQL Server 2005.&amp;#160; Both 92xx flags work in 2008, R2, and Denali CTP 3.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;© 2011 Paul White&lt;/p&gt;

&lt;p&gt;&lt;a href="mailto:SQLkiwi@gmail.com"&gt;SQLkiwi@gmail.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/SQL_Kiwi"&gt;@SQL_Kiwi&lt;/a&gt;&lt;/p&gt;</description></item><item><title>SQL Server 2008 R2 still requires a trace flag for Lock Pages in Memory</title><link>http://sqlblog.com/blogs/aaron_bertrand/archive/2011/02/07/sql-server-2008-r2-still-requires-a-trace-flag-for-lock-pages-in-memory.aspx</link><pubDate>Mon, 07 Feb 2011 16:32:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:33267</guid><dc:creator>AaronBertrand</dc:creator><description>Almost two years ago, I blogged that Lock Pages in Memory was finally &lt;a href="http://sqlblog.com/blogs/aaron_bertrand/archive/2009/04/24/big-news-lock-pages-in-memory-for-standard-edition.aspx" title="http://sqlblog.com/blogs/aaron_bertrand/archive/2009/04/24/big-news-lock-pages-in-memory-for-standard-edition.aspx" target="_blank"&gt;available to Standard Edition customers&lt;/a&gt; (Enterprise Edition customers had long been deemed smart enough to not abuse this feature).&amp;nbsp; In addition to applying a cumulative update (2005 SP3 CU4 or 2008 SP1 CU2), in order to take advantage of LPIM, you also had to enable trace flag 845. &lt;br&gt;&lt;p&gt;Since the trace flag isn't documented for SQL Server 2008 R2, several of us in the community assumed that it was no longer required (since it was introduced before 2008 R2 went RTM, and a trace flag is typically only introduced to change behavior after a product has been released).&amp;nbsp; We don't expect to see documentation stating that something *isn't* required, just like we don't expect to find a page on the SQL Server site that lists all of the features not supported by SQL Server.&lt;/p&gt;&lt;p&gt;As it turns out, the trace flag is still required for SQL Server 2008 R2.&amp;nbsp; Hopefully they will update R2's Books Online to reflect this (and Denali's, if it continues to be true for the next version of SQL Server).&lt;/p&gt;&lt;p&gt;&amp;nbsp; &lt;br&gt;&lt;/p&gt;</description></item><item><title>SQL Server challenge: show me trace flag 1118 is significant -- a quick update</title><link>http://sqlblog.com/blogs/linchi_shea/archive/2009/10/02/sql-server-challenge-show-me-trace-flag-1118-is-significant-a-quick-update.aspx</link><pubDate>Fri, 02 Oct 2009 15:42:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:17193</guid><dc:creator>Linchi Shea</dc:creator><description>&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;FONT face="Times New Roman" size=3&gt;I posted the following &lt;/FONT&gt;&lt;A href="http://sqlblog.com/blogs/linchi_shea/archive/2009/10/01/sql-server-challenge-show-me-trace-flag-1118-is-significant.aspx"&gt;&lt;FONT face="Times New Roman" color=#606420 size=3&gt;SQL Server challenge&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3&gt;&lt;FONT face="Times New Roman"&gt; yesterday:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;o:p&gt;&lt;FONT face="Times New Roman" size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 1in 0pt 0.5in;tab-stops:5.0in;"&gt;&lt;FONT size=3&gt;&lt;FONT face="Times New Roman"&gt;&lt;I style="mso-bidi-font-style:normal;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;COLOR:windowtext;mso-bidi-font-size:12.0pt;"&gt;Describe a reproducible workload that would see significant throughput improvement when trace flag 1118 is enabled.&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN style="FONT-WEIGHT:normal;COLOR:windowtext;mso-bidi-font-size:12.0pt;"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;o:p&gt;&lt;FONT face="Times New Roman" size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;FONT size=3&gt;&lt;FONT face="Times New Roman"&gt;In response, Konstantin Korobkov wanted to know whether the number of data files in tempdb would make a difference. &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;o:p&gt;&lt;FONT face="Times New Roman" size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;FONT face="Times New Roman" size=3&gt;I did test that scenario and did not see any difference. But I didn’t record the results. So I didn’t have any specific numbers to show. To be absolutely sure, I thought it would be better to reconfirm that, and I decided to run the same test: (1) with spT1118_v2 (see &lt;/FONT&gt;&lt;A href="http://sqlblog.com/blogs/linchi_shea/archive/2009/10/01/sql-server-challenge-show-me-trace-flag-1118-is-significant.aspx"&gt;&lt;FONT face="Times New Roman" color=#606420 size=3&gt;the previous post&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3&gt;&lt;FONT face="Times New Roman"&gt; for the code), (2) with a single data file in tempdb, and (3) with everything else being the same.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;o:p&gt;&lt;FONT face="Times New Roman" size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;FONT size=3&gt;&lt;FONT face="Times New Roman"&gt;The following chart summaries the test results with tempdb having a single data file:&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;&lt;IMG src="http://sqlblog.com/blogs/linchi_shea/attachment/17193.ashx"&gt; 
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;FONT size=3&gt;&lt;FONT face="Times New Roman"&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;FONT size=3&gt;&lt;FONT face="Times New Roman"&gt;&lt;o:p&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;Just the same as the results from the other scenarios in the previous posts (&lt;A href="http://sqlblog.com/blogs/linchi_shea/archive/2007/08/07/reduce-the-contention-on-tempdb-with-trace-flag-1118-to-enable-or-not-to-enable.aspx"&gt;&lt;FONT color=#606420&gt;[1]&lt;/FONT&gt;&lt;/A&gt;, &lt;A href="http://sqlblog.com/blogs/linchi_shea/archive/2007/08/10/reduce-the-contention-on-tempdb-with-trace-flag-1118-take-2.aspx"&gt;&lt;FONT color=#606420&gt;[2]&lt;/FONT&gt;&lt;/A&gt;, and&lt;A href="http://sqlblog.com/blogs/linchi_shea/archive/2009/10/01/sql-server-challenge-show-me-trace-flag-1118-is-significant.aspx"&gt;&lt;FONT color=#606420&gt; [3&lt;/FONT&gt;&lt;/A&gt;]), there was no significant difference whether or not trace flag 1118 was enabled.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;So the challenge stands.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/o:p&gt;
&lt;P class=MsoNormal style="MARGIN:0in 0in 0pt;"&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;</description></item></channel></rss>