<?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 'sqlpass', 'indexing', and 'sql'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=sqlpass,indexing,sql&amp;orTags=0</link><description>Search results matching tags 'sqlpass', 'indexing', and 'sql'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Using SQL Execution Plans to discover the Swedish alphabet</title><link>http://sqlblog.com/blogs/rob_farley/archive/2011/01/03/using-sql-execution-plans-to-discover-the-swedish-alphabet.aspx</link><pubDate>Mon, 03 Jan 2011 05:54:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:32237</guid><dc:creator>rob_farley</dc:creator><description>&lt;P&gt;SQL Server is quite remarkable in a bunch of ways. In this post, I’m using the way that the Query Optimizer handles LIKE to keep it SARGable, the Execution Plans that result, Collations, and PowerShell to come up with the Swedish alphabet.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msmvps.com/blogs/robfarley/archive/2010/01/22/sargable-functions-in-sql-server.aspx" target=_blank&gt;SARGability&lt;/A&gt; is the ability to seek for items in an index according to a particular set of criteria. If you don’t have SARGability in play, you need to scan the whole index (or table if you don’t have an index). For example, I can find myself in the phonebook easily, because it’s sorted by LastName and I can find Farley in there by moving to the Fs, and so on. I can’t find everyone in my suburb easily, because the phonebook isn’t sorted that way. I can’t even find people who have six letters in their last name, because also the book is sorted by LastName, it’s not sorted by LEN(LastName). This is all stuff I’ve looked at before, including in the &lt;A href="http://www.sqlbits.com/Sessions/Event7/Understanding_SARGability_to_make_your_queries_run_faster" target=_blank&gt;talk I gave at SQLBits in October 2010&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;If I try to find everyone who’s names start with F, I can do that using a query a bit like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;SELECT LastName FROM dbo.PhoneBook WHERE LEFT(LastName,1) = 'F';&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Unfortunately, the Query Optimizer doesn’t realise that all the entries that satisfy LEFT(LastName,1) = 'F' will be together, and it has to scan the whole table to find them.&lt;/P&gt;
&lt;P&gt;&lt;IMG style="BACKGROUND-IMAGE:none;BORDER-BOTTOM:0px;BORDER-LEFT:0px;PADDING-LEFT:0px;PADDING-RIGHT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;PADDING-TOP:0px;" title=image border=0 alt=image src="http://sqlblog.com/blogs/rob_farley/image_0BB56CF3.png" width=595 height=143&gt;&lt;/P&gt;
&lt;P&gt;But if I write:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;SELECT LastName FROM dbo.PhoneBook WHERE LastName LIKE 'F%';&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;then SQL is smart enough to understand this, and performs an Index Seek instead.&lt;/P&gt;
&lt;P&gt;&lt;IMG style="BACKGROUND-IMAGE:none;BORDER-BOTTOM:0px;BORDER-LEFT:0px;PADDING-LEFT:0px;PADDING-RIGHT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;PADDING-TOP:0px;" title=image border=0 alt=image src="http://sqlblog.com/blogs/rob_farley/image_0F7311C3.png" width=566 height=133&gt;&lt;/P&gt;
&lt;P&gt;To see why, I look further into the plan, in particular, the properties of the Index Seek operator. The ToolTip shows me what I’m after:&lt;/P&gt;
&lt;P&gt;&lt;IMG style="BACKGROUND-IMAGE:none;BORDER-BOTTOM:0px;BORDER-LEFT:0px;PADDING-LEFT:0px;PADDING-RIGHT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;PADDING-TOP:0px;" title=image border=0 alt=image src="http://sqlblog.com/blogs/rob_farley/image_14754F72.png" width=302 height=200&gt;&lt;/P&gt;
&lt;P&gt;You’ll see that it does a Seek to find any entries that are at least F, but not yet G. There’s an extra Predicate in there (a Residual Predicate if you like), which checks that each LastName is really LIKE F% – I suppose it doesn’t consider that the Seek Predicate is quite enough – but most of the benefit is seen by its working out the Seek Predicate, filtering to just the “at least F but not yet G” section of the data.&lt;/P&gt;
&lt;P&gt;This got me curious though, particularly about where the G comes from, and whether I could leverage it to create the Swedish alphabet.&lt;/P&gt;
&lt;P&gt;I know that in the Swedish language, there are three extra letters that appear at the end of the alphabet. One of them is ä that appears in the word Västerås. It turns out that Västerås is quite hard to find in an index when you’re looking it up in a Swedish map. I talked about this briefly in my five-minute &lt;A href="http://bit.ly/RFCollation" target=_blank&gt;talk on Collation&lt;/A&gt; from SQLPASS (the one which was slightly less than serious).&lt;/P&gt;
&lt;P&gt;So by looking at the plan, I can work out what the next letter is in the alphabet of the collation used by the column. In other words, if my alphabet were Swedish, I’d be able to tell what the next letter after F is – just in case it’s not G.&lt;/P&gt;
&lt;P&gt;It turns out it is… Yes, the Swedish letter after F is G. But I worked this out by using a copy of my PhoneBook table that used the Finnish_Swedish_CI_AI collation. I couldn’t find how the Query Optimizer calculates the G, and my friend &lt;A href="http://sqlblog.com/blogs/paul_white/" target=_blank&gt;Paul White&lt;/A&gt; (&lt;A href="http://twitter.com/SQL_Kiwi" target=_blank&gt;@SQL_Kiwi&lt;/A&gt;) tells me that it’s frustratingly internal to the QO. He’s particularly smart, even if he is from New Zealand.&lt;/P&gt;
&lt;P&gt;To investigate further, I decided to do some PowerShell, leveraging the &lt;A href="http://sqlblog.com/blogs/rob_farley/archive/2010/12/07/powershell-to-fetch-a-sql-execution-plan.aspx" target=_blank&gt;Get-SqlPlan function&lt;/A&gt; that I blogged about recently (make sure you also have the SqlServerCmdletSnapin100 snap-in added. To do that, run &lt;EM&gt;get-pssnapin -reg&lt;/EM&gt; to see if it's on the machine, and &lt;EM&gt;get-pssnapin -reg | add-pssnapin&lt;/EM&gt; to make the cmdlet available).&lt;/P&gt;
&lt;P&gt;I started by indicating that I was going to use Finnish_Swedish_CI_AI as my collation of choice, and that I’d start whichever letter came straight after the number 9. I figure that this is a cheat’s way of guessing the first letter of the alphabet (but it doesn’t actually work in Unicode – luckily I’m using varchar not nvarchar. Actually, there are a few aspects of this code that only work using ASCII, so apologies if you were wanting to apply it to Greek, Japanese, etc). I also initialised my $alphabet variable.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;$collation = 'Finnish_Swedish_CI_AI'; &lt;BR&gt;$firstletter = '9'; &lt;BR&gt;$alphabet = '';&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now I created the table for my test. A single field would do, and putting a Clustered Index on it would suffice for the Seeks. &lt;EM&gt;[Edit: You may need to insert some rows if you find that it's producing&amp;nbsp;an Index Scan. Theoretically it should prefer to Scan,&amp;nbsp;knowing there's&amp;nbsp;no rows, but my tests showed it would always Seek]&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;Invoke-Sqlcmd -server . -data tempdb -query "create table dbo.collation_test (col varchar(10) collate $collation primary key);"&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now I get into the looping. &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;$c = $firstletter; &lt;BR&gt;$stillgoing = $true; &lt;BR&gt;while ($stillgoing) &lt;BR&gt;{&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I construct the query I want, seeking for entries which start with whatever $c has reached, and get the plan for it:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;$query = "select col from dbo.collation_test where col like '$($c)%';"; &lt;BR&gt;[xml] $pl = get-sqlplan $query "." "tempdb";&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;At this point, my $pl variable is a scary piece of XML, representing the execution plan. A bit of hunting through it showed me that the EndRange element contained what I was after, and that if it contained NULL, then I was done.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;$stillgoing = ($pl.ShowPlanXML.BatchSequence.Batch.Statements.StmtSimple.QueryPlan.RelOp.IndexScan.SeekPredicates.SeekPredicateNew.SeekKeys.EndRange -ne $null);&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now I could grab the value out of it (which came with apostrophes that needed stripping), and append that to my $alphabet variable.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;&amp;nbsp; if ($stillgoing) &lt;BR&gt;&amp;nbsp; {&amp;nbsp; &lt;BR&gt;$c=$pl.ShowPlanXML.BatchSequence.Batch.Statements.StmtSimple.QueryPlan.RelOp.IndexScan.SeekPredicates.SeekPredicateNew.SeekKeys.EndRange.RangeExpressions.ScalarOperator.ScalarString.Replace("'",""); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $alphabet += $c; &lt;BR&gt;&amp;nbsp; }&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Finally, finishing the loop, dropping the table, and showing my alphabet!&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;} &lt;BR&gt;Invoke-Sqlcmd -server . -data tempdb -query "drop table dbo.collation_test;"; &lt;BR&gt;$alphabet;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;When I run all this, I see that the Swedish alphabet is ABCDEFGHIJKLMNOPQRSTUVXYZÅÄÖ, which matches what I see at &lt;A href="http://en.wikipedia.org/wiki/Swedish_orthography" target=_blank&gt;Wikipedia&lt;/A&gt;. Interesting to see that the letters on the end are still there, even with Case Insensitivity. Turns out they’re not just “letters with accents”, they’re letters in their own right.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://sqlblog.com/blogs/rob_farley/image_528E6A23.png"&gt;&lt;IMG style="BACKGROUND-IMAGE:none;BORDER-BOTTOM:0px;BORDER-LEFT:0px;PADDING-LEFT:0px;PADDING-RIGHT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;PADDING-TOP:0px;" title=image border=0 alt=image src="http://sqlblog.com/blogs/rob_farley/image_thumb_0511C796.png" width=609 height=292&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;I’m sure you gave up reading long ago, and really aren’t that&amp;nbsp;grabbed about the idea of doing this using PowerShell. I chose PowerShell because I’d already come up with an easy way of grabbing the estimated plan for a query, and PowerShell does allow for easy navigation of XML.&lt;/P&gt;
&lt;P&gt;I find the most interesting aspect of this as the fact that the Query Optimizer uses the next letter of the alphabet to maintain the SARGability of LIKE. &lt;A href="https://connect.microsoft.com/SQLServer/feedback/details/526431/make-more-functions-sargable" target=_blank&gt;I’m hoping they do something similar for a whole bunch of operations&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Oh, and the fact that you know how to find stuff in the IKEA catalogue.&lt;/P&gt;
&lt;HR&gt;

&lt;P&gt;Footnote: &lt;/P&gt;
&lt;P&gt;If you are interested in whether this works in other languages, you might want to consider the following screenshot, which shows that in principle, it should work with Japanese. It might be a bit harder to run this in PowerShell though, as I’m not sure how it translates. In Hiragana, the Japanese alphabet starts あ, ぃ, ぅ, ぇ, ぉ, ...&lt;/P&gt;
&lt;P&gt;&lt;A href="http://sqlblog.com/blogs/rob_farley/image_20F2D6C1.png"&gt;&lt;IMG style="BACKGROUND-IMAGE:none;BORDER-BOTTOM:0px;BORDER-LEFT:0px;PADDING-LEFT:0px;PADDING-RIGHT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;PADDING-TOP:0px;" title=image border=0 alt=image src="http://sqlblog.com/blogs/rob_farley/image_thumb_57DC8F2D.png" width=644 height=413&gt;&lt;/A&gt;&lt;/P&gt;</description></item><item><title>Inverse Predicates - look both ways before you cross</title><link>http://sqlblog.com/blogs/rob_farley/archive/2010/11/08/inverse-predicates-look-both-ways-before-you-cross.aspx</link><pubDate>Mon, 08 Nov 2010 21:53:21 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:30273</guid><dc:creator>rob_farley</dc:creator><description>&lt;p&gt;When I’m at the &lt;a href="http://www.sqlpass.org/summit/na2010" target="_blank"&gt;PASS Summit&lt;/a&gt; in Seattle this week, I will need to remember that I can’t just step onto the road if I’m walking along the footpath on the right-hand side. In the UK and Australia, where we drive the correct side, it’s fine (just don’t tell my kids), because the cars that are nearest me are coming towards me – except of course, the idiots who are reading blog posts while they’re driving. They could be anywhere.&lt;/p&gt;  &lt;p&gt;I should also learn to stop picking on left-handed people for being ‘&lt;a href="http://en.wiktionary.org/wiki/sinister" target="_blank"&gt;sinister&lt;/a&gt;’. The word ‘sinister’ comes from the Latin word for left, and is associated with the fact that writing with your left hand is unnatural – some would even use the word ‘evil’. My beautiful wife is left-handed, and she’s definitely not sinister or evil. So really I should just pick on left-handed people for their inability to write on whiteboards, not for their sinisterisity. &lt;/p&gt;  &lt;p&gt;You see, the world is designed for right-handed people. Even cars are designed to be driven by right-handed people, and this is why in normal places, the steering wheel is positioned on the right-hand side of the car so that the right-hand can be in control of it all the time, with the left hand being free to change gears, use the indicator, change the radio stations, drink coffee, tweet, etc – all those things that are less important than controlling the car.&lt;/p&gt;  &lt;p&gt;And so we consider queries – in particular, the joining of tables. We might include something in our FROM clause like:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;FROM dbo.Deliveries AS d        &lt;br /&gt;JOIN dbo.Orders AS o         &lt;br /&gt;ON d.DeliveryDate = DATEADD(day,1,o.OrderDate)&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This aligns nicely with our thoughts around SARGability, which suggests that you leave the left-hand side of predicates untouched. Unfortunately, I don’t tend to write my ON clause predicates this way around, because I like to focus on the table I’ve just introduced into the mix. I write my queries like:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;FROM dbo.Deliveries AS d        &lt;br /&gt;JOIN dbo.Orders AS o         &lt;br /&gt;ON o.OrderDate = DATEADD(day,-1,d.DeliveryDate)&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;You’ll notice that I’ve inverted the predicate, because I still like the idea of keeping the left-hand side untouched, but at this point, I want to ask you to have a think about what we’re trying to achieve.&lt;/p&gt;  &lt;p&gt;I’ve written before about how the point of SARGability is to allow an index to be used nicely. Think of the phone book, and how you can easily find the name you want (also, just for fun, think of the Japanese phone book, and how you can’t find names in it unless you understand how their alphabet is ordered). It’s very similar with our Deliveries and Orders tables – we can find a particular date in it if there is an index on that field.&lt;/p&gt;  &lt;p&gt;But which query should we think about? The first one, where we’re trying to find a Delivery, or the second, where we’re trying to find an Order.&lt;/p&gt;  &lt;p&gt;Naturally, being a data question, the answer is “It depends”. And that’s right – it depends on what your query is actually doing.&lt;/p&gt;  &lt;p&gt;If you’re just creating a query, and have a WHERE clause that contains something like: WHERE o.OrderDate = '20101106', then you’re okay. You know that you can easily find the Orders you want, and need the ON clause in the first example (to help find the Delivery). But if you’re creating a &lt;em&gt;view&lt;/em&gt;, and people can use this query in a variety of ways, then you don’t know which side you’re going to start.&lt;/p&gt;  &lt;p&gt;When SARGability is working nicely, we probably see the execution plan using an Index Seek, and can notice in that Seek’s properties that there is a Seek Predicate being used to support that. You can also see it in the ToolTip, as I’ve shown in the picture below. I ran the query &lt;em&gt;SELECT * FROM Production.Product WHERE ProductID = 316;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/rob_farley/image_432BF6A4.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/rob_farley/image_thumb_67CCE84E.png" width="593" height="554" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If there are other predicates involved, that aren’t so SARGable (quite probably nothing to do with functions, rather than a choice of index), then we see this reflected in the Predicate property. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/rob_farley/image_18EC22EF.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/rob_farley/image_thumb_2C990C83.png" width="777" height="615" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Here I’m filtering on the SafetyStockLevel as well as the ProductID. It uses the ProductID for the Seek, but checks all the results of this Seek using the SafetyStockLevel value, before returning anything out of the Seek operator. We’re not doing a scan with SafetyStockLevel, but we are checking every value returned by the Seek Predicate. This could be improved with an index across both columns (together, not individually), but if the Seek is effective, then the regular Predicate won’t have to be applied to many rows anyway.&lt;/p&gt;  &lt;p&gt;When thinking about your indexes, do remember that included_columns (rather than key_columns) are not ordered, so any predicates involving them won’t be Seek Predicates. If the phone book were only on LastName, and FirstName was an included columnn, then finding me in there would mean checking all the farleys for Rob, rather than finding the Farleys and then continuing the seek to find the Rob entry.&lt;/p&gt;  &lt;p&gt;Back with our orders and deliveries, we see an interesting phenomenon at play.&lt;/p&gt;  &lt;p&gt;If I create a view using the first FROM clause, and filter the view on OrderDate, I might get a nice plan, involving Seeks.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/rob_farley/image_1977DFD7.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/rob_farley/image_thumb_03ADF77A.png" width="764" height="666" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This is an excellent plan for this particular query, but if I start with the DeliveryDate, then it’s not so nice.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/rob_farley/image_564C61A9.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/rob_farley/image_thumb_5573FBBF.png" width="833" height="659" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The cost of this is much larger – probably orders of magnitude larger. But if I use the other ON clause, I see the same behaviour with the columns switched (good performance if I start with the DeliveryDate, bad performance if I start with OrderDate).&lt;/p&gt;  &lt;p&gt;Ideally, we can do a Seek to find the records we want, regardless of whether we want to look up the records by DeliveryDate or by OrderDate. This would mean getting a Seek Predicate both times to see SARGability in use.&lt;/p&gt;  &lt;p&gt;Having shown you earlier the example that used both a Seek Predicate AND a Predicate in the same query provides the key here...&lt;/p&gt;  &lt;p&gt;Use both! (Yes, work out the inverse predicate, and include it)&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;FROM dbo.Deliveries AS d        &lt;br /&gt;JOIN dbo.Orders AS o         &lt;br /&gt;ON d.DeliveryDate = DATEADD(day,1,o.OrderDate)        &lt;br /&gt;AND o.OrderDate = DATEADD(day,-1,d.DeliveryDate)&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The predicate which isn’t suitable for the Seek will be used as a regular Predicate, while the SARGable one gets the effective Seek Predicate. Now you can the best of both worlds, but you will need to work out the inverse of some of your predicates. &lt;/p&gt;  &lt;p&gt;It’s not hard, but it may have great reward. In the plans below, I’ve created a view like the notice the fact that when we look up records with a known OrderDate, we can seek for the Order, and then look up the Delivery using the transformed OrderDate. Checking that the OrderDate matches the transformed DeliveryDate falls into the Predicate, not the Seek Predicate.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/rob_farley/image_6D97661A.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/rob_farley/image_thumb_28BB1C19.png" width="779" height="696" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Conversely, if we have the DeliveryDate, then we can seek to find the Delivery, and then look up the Order using an appropriate Seek Predicate, with the other becoming the regular Predicate.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/rob_farley/image_39BF49FC.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/rob_farley/image_thumb_0DA24D0B.png" width="774" height="705" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;So now when you want to create views for a variety of uses, you can hopefully see some potential in saying the same thing from both perspectives. Don’t just think left-to-right – consider all the different ways you could approach your data. Just maybe don’t try to write your execution plan on a whiteboard.&lt;/p&gt;</description></item></channel></rss>