<?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 tags 'Conversions' and 'Seeks'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=Conversions,Seeks&amp;orTags=0</link><description>Search results matching tags 'Conversions' and 'Seeks'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Dynamic Seeks and Hidden Implicit Conversions</title><link>http://sqlblog.com/blogs/paul_white/archive/2012/01/17/dynamic-seeks-and-hidden-implicit-conversions.aspx</link><pubDate>Tue, 17 Jan 2012 13:37:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:41097</guid><dc:creator>Paul White</dc:creator><description>&lt;p&gt;Most people know that a LIKE predicate with only a trailing wildcard can usually use an index seek:&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;&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; &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;'D%'&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/image_3C27CA3C.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="Index Seek on LIKE" border="0" alt="Index Seek on LIKE" width="403" height="334" src="http://sqlblog.com/blogs/paul_white/image_thumb_4B7B2C4B.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the execution plan shows, SQL Server determines a covering range (which depends on the collation), seeks the string index using the range as the start and end points of a partial scan, and applies the original LIKE condition as a residual predicate to just the rows that match the initial seek operation.&amp;nbsp; Specifically, the Storage Engine seeks the index to locate rows in the covering range, and the Query Processor applies the residual predicate (the LIKE) to the rows it receives.&lt;/p&gt;

&lt;h3&gt;Dynamic Seeks&lt;/h3&gt;

&lt;p&gt;But what if the LIKE search term is in a variable?&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;DECLARE&lt;/span&gt; @&lt;span style="color:#0000ff;"&gt;Like&lt;/span&gt; NVARCHAR(50) = N&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;nbsp;&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;&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; &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; @&lt;span style="color:#0000ff;"&gt;Like&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;SQL Server can still perform a seek here, but it needs to determine the covering seek range for the search term at execution time, not at compilation time:&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/image_4FA50410.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="Dynamic Index Seek" border="0" alt="Dynamic Index Seek" width="632" height="483" src="http://sqlblog.com/blogs/paul_white/image_thumb_5362A8E0.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The plan now contains an extra Constant Scan,&amp;nbsp; a Compute Scalar and a Nested Loops Join.&amp;nbsp; These operators are interesting because they have zero cost estimates: no CPU, no I/O, nothing.&amp;nbsp; That’s because they are purely architectural: a workaround for the fact that SQL Server cannot currently perform a dynamic seek within the Index Seek operator itself.&amp;nbsp; To avoid affecting plan choices, this extra machinery is costed at zero.&lt;/p&gt;

&lt;p&gt;The Constant Scan produces a single in-memory row with no columns.&amp;nbsp; The Compute Scalar defines expressions to describe the covering seek range (using the runtime value of the @Like variable).&amp;nbsp; Finally, the Nested Loops Join drives the seek using the computed range information as correlated values.&lt;/p&gt;

&lt;p&gt;The upper tooltip shows that the Compute Scalar uses three internal functions, &lt;b&gt;LikeRangeStart&lt;/b&gt;, &lt;b&gt;LikeRangeEnd&lt;/b&gt;, and &lt;b&gt;LikeRangeInfo&lt;/b&gt;.&amp;nbsp; The first two functions describe the range as an open interval.&amp;nbsp; The third function returns a set of flags encoded in an integer, that are used internally to define certain seek properties for the Storage Engine.&amp;nbsp; The lower tooltip shows the seek on the open interval described by the result of &lt;i&gt;LikeRangeStart&lt;/i&gt; and &lt;i&gt;LikeRangeEnd&lt;/i&gt;, and the application of the residual predicate ‘LIKE @Like’.&lt;/p&gt;

&lt;h3&gt;More Dynamic Seeks&lt;/h3&gt;

&lt;p&gt;Something very similar occurs in plans that use IN or OR with variables:&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;DECLARE&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:#0000ff;"&gt;INTEGER&lt;/span&gt; = 320,&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:#0000ff;"&gt;INTEGER&lt;/span&gt; = 325,&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:#0000ff;"&gt;INTEGER&lt;/span&gt; = 330&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;nbsp;&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;&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; &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 &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (@1,@2,@3);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/image_506D442D.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="Dynamic Seek With IN and OR" border="0" alt="Dynamic Seek With IN and OR" width="647" height="574" src="http://sqlblog.com/blogs/paul_white/image_thumb_17FF1D55.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have three ranges: one for each of the variables in the original query.&amp;nbsp; The Compute Scalar operators again define three columns containing the start and end of the range, and the associated informational flags (previously seen as a result of the &lt;i&gt;LikeRangeInfo&lt;/i&gt; function).&amp;nbsp; This time, we see the decimal representation of these flags, which happens to be 62 for an equality comparison.&amp;nbsp; The IN expands to (ProductID = @1 OR ProductID = @2 OR ProductID = @3), so each of the ‘ranges’ here is in fact a single value, so the start and end range values are the same in each Compute Scalar.&lt;/p&gt;

&lt;p&gt;The three dynamic ranges are concatenated, sorted (so any overlapping ranges appear next to each other in the stream) and the Merge Interval collapses these intervals into one or more disjoint (non-overlapping) ranges.&amp;nbsp; This is important, because the three variables might, for example, all contain the same value, and it would be incorrect to return that value three times.&amp;nbsp; Anyway, for each disjoint range produced, the Nested Loops Join drives a new seek of the Clustered Index.&amp;nbsp; The overall effect is that an arbitrary number of possibly overlapping ranges are computed, merged, and then used to drive one or more seek operations. The final result of the query will be the combination of all the seek results, as you would expect.&lt;/p&gt;

&lt;h3&gt;Hidden Conversions&lt;/h3&gt;

&lt;p&gt;The following example contains a table with DATETIME2 values, and a query with a expression that at first sight seems unlikely to be able to seek on an index (the variable is typed as DATE, and there is a CONVERT function applied to the DATETIME2 column):&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;DECLARE&lt;/span&gt; @Example &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; (date_time DATETIME2 &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&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;nbsp;&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 @Example (date_time) &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;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;'20110101 12:34:56'&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;nbsp;&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;DECLARE&lt;/span&gt; @&lt;span style="color:#0000ff;"&gt;date&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATE&lt;/span&gt; = &lt;span style="color:#006080;"&gt;'2011-01-01'&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;nbsp;&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; @Example &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; e &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;    @&lt;span style="color:#0000ff;"&gt;date&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;CONVERT&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;DATE&lt;/span&gt;, e.date_time);&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Nevertheless, a query plan that uses a seek can be produced:&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/image_02C0F1E0.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="GetRangeThroughConvert" border="0" alt="GetRangeThroughConvert" width="702" height="461" src="http://sqlblog.com/blogs/paul_white/image_thumb_2DB8DFE5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, neither SSMS or Plan Explorer will show the contents of the Compute Scalar (this is probably just an oversight, rather than deliberate concealment!).&amp;nbsp; We have to open the XML form of the execution plan to see the three familiar expressions, wrapped in a Value Vector (just a fancy container for multiple expressions).&lt;/p&gt;

&lt;p&gt;Another internal function, &lt;b&gt;GetRangeThroughConvert&lt;/b&gt;, is responsible for determining the the range of DATETIME2 values covered by the DATE variable @date, and the informational flags needed.&amp;nbsp; In the same way the engine works out covering ranges for some LIKE predicates, this function determines ranges where certain problematic type conversions are required.&amp;nbsp; Otherwise, the machinery is the same: a range description is defined by the Compute Scalar, and the Nested Loops Join driving a seek using those values.&lt;/p&gt;

&lt;h3&gt;More Hidden Conversions&lt;/h3&gt;

&lt;p&gt;There is another related internal function used when the Query Processor needs to determine a range for a comparison between different data types.&amp;nbsp; This example returns rows based on a greater-than-or-equal comparison between DATE column values and the DATETIME return value of the GETDATE() intrinsic function:&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;DECLARE&lt;/span&gt; @Example &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; (col1 &lt;span style="color:#0000ff;"&gt;date&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&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;FROM&lt;/span&gt; @Example &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; e &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; e.col1 &amp;gt;= DATEADD(&lt;span style="color:#0000ff;"&gt;DAY&lt;/span&gt;, -7, GETDATE());&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/image_1C850242.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="GetRangeWithMismatchedTypes" border="0" alt="GetRangeWithMismatchedTypes" width="541" height="351" src="http://sqlblog.com/blogs/paul_white/image_thumb_6EB7397C.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, the SSMS graphical plan and Plan Explorer cannot display the contents of the Value Vector, so we have to dig into the XML again.&amp;nbsp; The function evaluates the DATEADD(GETDATE()) expression, computes the open-interval start point of a DATE range accounting for the conversion from DATETIME to DATE, and specifies NULL as the end of the range (since this is a &amp;gt;= comparison, there is no end value).&amp;nbsp; The flags value in this case is 22 (the flags for a &amp;gt;= seek operation).&lt;/p&gt;

&lt;h3&gt;Everything All At Once&lt;/h3&gt;

&lt;p&gt;This last example features all sorts type sloppiness, resulting in an execution plan that uses &lt;b&gt;GetRangeThroughConvert&lt;/b&gt; on the string expression and &lt;b&gt;GetRangeThroughConvert&lt;/b&gt; &lt;i&gt;on the result of&lt;/i&gt; &lt;b&gt;GetRangeWithMismatchedTypes&lt;/b&gt; applied to the result of the GETDATE function.&amp;nbsp; The whole thing is then wrapped in a dynamic seek with the Merge Interval enforcing the (annoying) BETWEEN requirement that the first parameter must be less than or equal to the second.&amp;nbsp; See if you can work out all the conversions necessary for this query, using the rules of data type precedence.&amp;nbsp; It is really quite impressive that this example of lazy T-SQL coding results in an index seek, don’t you think?&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;DECLARE&lt;/span&gt; @Example &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; (col1 DATETIME &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&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;FROM&lt;/span&gt; @Example &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; e&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;span style="color:#0000ff;"&gt;CONVERT&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;DATE&lt;/span&gt;, e.col1) &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;'20000101'&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; GETDATE();&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/image_2BF7EE44.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="Merge Interval Implcit Conversions" border="0" alt="Merge Interval With Everything" width="651" height="450" src="http://sqlblog.com/blogs/paul_white/image_thumb_1AC410A1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;SQL Server works quite hard sometimes to produce index seeks where they might seem unlikely.&amp;nbsp; This is a good thing, and it would be great to see this capability &lt;a href="http://connect.microsoft.com/SQLServer/feedback/details/526431/make-more-functions-sargable"&gt;extended further&lt;/a&gt; in future.&amp;nbsp; The downside is that this extra effort means you are less likely to see an Index Scan when you have done something daft with data types.&lt;/p&gt;

&lt;p&gt;Why is this a bad thing if you get a seek anyway?&amp;nbsp; The problem is that these hidden implicit conversions can result in inaccurate cardinality and distribution estimations at any stage of the plan.&amp;nbsp; So, even if you get a seek, the plan might be way off overall.&amp;nbsp; If that isn’t persuasive enough, consider this: will having hidden nested range calculations improve your chances of getting a good query plan?&amp;nbsp; Probably not, no.&amp;nbsp; Be very aware of types, and in particular of the types returned by functions and expressions.&amp;nbsp; If in doubt, use SELECT INTO to materialize the results of an expression or query, and check the types of the columns produced.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;i&gt;&lt;/i&gt;&lt;/p&gt;

  &lt;hr&gt;Note: if you have any scripts that trawl the plan cache looking for implicit conversions (CONVERT_IMPLICIT), you might want to look into updating them to check for these conversions too.&amp;nbsp; Not all conversions are bad ones, of course :) 

  &lt;br&gt;

  &lt;hr&gt;&lt;/blockquote&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;

&lt;h4&gt;Further Reading:&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/b/craigfr/archive/2008/06/05/implicit-conversions.aspx"&gt;Implicit Conversions&lt;/a&gt; – Craig Freedman 

  &lt;br&gt;&lt;a href="http://blogs.msdn.com/b/craigfr/archive/2010/01/20/more-on-implicit-conversions.aspx"&gt;More on Implicit Conversions&lt;/a&gt; – Craig Freedman 

  &lt;br&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/paul_white/archive/2011/07/19/join-performance-implicit-conversions-and-residuals.aspx"&gt;Join Performance, Implicit Conversions, and Residuals&lt;/a&gt; - Me&lt;/p&gt;</description></item></channel></rss>