<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	
	>
<channel>
	<title>
	Comments on: The SQL Query Optimizer – when Logical Order can get it wrong	</title>
	<atom:link href="https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/feed/" rel="self" type="application/rss+xml" />
	<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/</link>
	<description></description>
	<lastBuildDate>Thu, 03 Jan 2013 16:48:02 +0000</lastBuildDate>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>
		By: Chris Adkin		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2196</link>

		<dc:creator><![CDATA[Chris Adkin]]></dc:creator>
		<pubDate>Thu, 03 Jan 2013 16:48:02 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2196</guid>

					<description><![CDATA[Rob,
You may be alluding to what the optimizer team refer to as the ascending key problem, whereby data gets added to a table in ascending key order, for large tables ( opposite of the &#039;Small&#039; table you mentioned - I know ), this can be mitigated against via trace flag 2371. You may also want to look at connect item 676224, another popular database engine includes the ability for hints to be used on statements that specify:
1. That data in the relevant table(s) should be sampled in order to produce better plans.
2. How aggresively the sampling should be
Refer to connect item 676224]]></description>
			<content:encoded><![CDATA[<p>Rob,<br />
You may be alluding to what the optimizer team refer to as the ascending key problem, whereby data gets added to a table in ascending key order, for large tables ( opposite of the &#8216;Small&#8217; table you mentioned &#8211; I know ), this can be mitigated against via trace flag 2371. You may also want to look at connect item 676224, another popular database engine includes the ability for hints to be used on statements that specify:<br />
1. That data in the relevant table(s) should be sampled in order to produce better plans.<br />
2. How aggresively the sampling should be<br />
Refer to connect item 676224</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Rob Farley		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2195</link>

		<dc:creator><![CDATA[Rob Farley]]></dc:creator>
		<pubDate>Wed, 02 Jan 2013 05:09:46 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2195</guid>

					<description><![CDATA[Ok Simon... how about in AdventureWorksDW, which has 60K records in dbo.FactInternetSales? I get it&#039;s still not huge, but it shows that it&#039;s easy to have a bad plan come out.

CREATE INDEX ix1 ON dbo.FactInternetSales(OrderDateKey) INCLUDE (UnitPrice);

CREATE INDEX ix2 ON dbo.FactInternetSales(UnitPrice) INCLUDE (OrderDateKey);

SELECT MIN(OrderDateKey)
FROM dbo.FactInternetSales
WHERE UnitPrice between 0 and 100;
--Prefers ix1. 20 reads

SELECT MIN(OrderDateKey)
FROM dbo.FactInternetSales
WHERE UnitPrice between 600 and 700;
--Prefers ix2. 2 reads.

SELECT MIN(OrderDateKey)
FROM dbo.FactInternetSales WITH (INDEX(ix2))
WHERE UnitPrice between 0 and 100;
--Forced ix2. 150 reads.

Of course, with a correlation between the two fields, it could be possible to show an example of ix1 being particularly nasty as well.]]></description>
			<content:encoded><![CDATA[<p>Ok Simon&#8230; how about in AdventureWorksDW, which has 60K records in dbo.FactInternetSales? I get it&#8217;s still not huge, but it shows that it&#8217;s easy to have a bad plan come out.</p>
<p>CREATE INDEX ix1 ON dbo.FactInternetSales(OrderDateKey) INCLUDE (UnitPrice);</p>
<p>CREATE INDEX ix2 ON dbo.FactInternetSales(UnitPrice) INCLUDE (OrderDateKey);</p>
<p>SELECT MIN(OrderDateKey)<br />
FROM dbo.FactInternetSales<br />
WHERE UnitPrice between 0 and 100;<br />
&#8211;Prefers ix1. 20 reads</p>
<p>SELECT MIN(OrderDateKey)<br />
FROM dbo.FactInternetSales<br />
WHERE UnitPrice between 600 and 700;<br />
&#8211;Prefers ix2. 2 reads.</p>
<p>SELECT MIN(OrderDateKey)<br />
FROM dbo.FactInternetSales WITH (INDEX(ix2))<br />
WHERE UnitPrice between 0 and 100;<br />
&#8211;Forced ix2. 150 reads.</p>
<p>Of course, with a correlation between the two fields, it could be possible to show an example of ix1 being particularly nasty as well.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Simon Sabin		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2194</link>

		<dc:creator><![CDATA[Simon Sabin]]></dc:creator>
		<pubDate>Tue, 01 Jan 2013 15:51:53 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2194</guid>

					<description><![CDATA[Having so few rows in the table make this a little contrite. The indexes only have 4 leaf pages to read. All data is found on one page and so its a question in both of scanning a single page for a value.
It would be helpful to show this with more data where the impact is significant.]]></description>
			<content:encoded><![CDATA[<p>Having so few rows in the table make this a little contrite. The indexes only have 4 leaf pages to read. All data is found on one page and so its a question in both of scanning a single page for a value.<br />
It would be helpful to show this with more data where the impact is significant.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Rob Farley		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2193</link>

		<dc:creator><![CDATA[Rob Farley]]></dc:creator>
		<pubDate>Mon, 31 Dec 2012 03:16:34 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2193</guid>

					<description><![CDATA[Ian: Thanks]]></description>
			<content:encoded><![CDATA[<p>Ian: Thanks</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Rob Farley		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2192</link>

		<dc:creator><![CDATA[Rob Farley]]></dc:creator>
		<pubDate>Mon, 31 Dec 2012 03:14:40 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2192</guid>

					<description><![CDATA[Martin: Yes - if it thinks the range is wide enough and low enough selectivity it can decide to go from both sides. But in that scenario you can solve it easily with a composite index, because the predicate is an equality.]]></description>
			<content:encoded><![CDATA[<p>Martin: Yes &#8211; if it thinks the range is wide enough and low enough selectivity it can decide to go from both sides. But in that scenario you can solve it easily with a composite index, because the predicate is an equality.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Ian Yates		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2191</link>

		<dc:creator><![CDATA[Ian Yates]]></dc:creator>
		<pubDate>Mon, 31 Dec 2012 03:09:40 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2191</guid>

					<description><![CDATA[Great post! I really liked the clear explanations  I think I shall use them in real life when trying to explain some of this behaviour to others (or just point them to this blog)]]></description>
			<content:encoded><![CDATA[<p>Great post! I really liked the clear explanations  I think I shall use them in real life when trying to explain some of this behaviour to others (or just point them to this blog)</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Martin Smith		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2190</link>

		<dc:creator><![CDATA[Martin Smith]]></dc:creator>
		<pubDate>Mon, 31 Dec 2012 00:37:06 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2190</guid>

					<description><![CDATA[Actually the link in my first post does show sometimes SQL Server will generate such a plan calculating the MIN and MAX separately (in that case it also has added lookups which make things worse.)]]></description>
			<content:encoded><![CDATA[<p>Actually the link in my first post does show sometimes SQL Server will generate such a plan calculating the MIN and MAX separately (in that case it also has added lookups which make things worse.)</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Rob Farley		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2189</link>

		<dc:creator><![CDATA[Rob Farley]]></dc:creator>
		<pubDate>Sun, 30 Dec 2012 23:45:07 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2189</guid>

					<description><![CDATA[Your points are all valid, and again I&#039;ll say that designing indexes around business knowledge is important. Many business scenarios would consistently be much closer to the best case, and it would be foolish to settle for the &#034;least bad worst case&#034; alternative.
Obviously the queries can be forced into either plan, once the developers have considered their options.
And your query example doesn&#039;t work. If you need both MIN and MAX you&#039;d need to approach from both ends, and your equality predicate causes a simple composite index most effective.]]></description>
			<content:encoded><![CDATA[<p>Your points are all valid, and again I&#8217;ll say that designing indexes around business knowledge is important. Many business scenarios would consistently be much closer to the best case, and it would be foolish to settle for the &quot;least bad worst case&quot; alternative.<br />
Obviously the queries can be forced into either plan, once the developers have considered their options.<br />
And your query example doesn&#8217;t work. If you need both MIN and MAX you&#8217;d need to approach from both ends, and your equality predicate causes a simple composite index most effective.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Martin Smith		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2188</link>

		<dc:creator><![CDATA[Martin Smith]]></dc:creator>
		<pubDate>Sun, 30 Dec 2012 17:46:28 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2188</guid>

					<description><![CDATA[Just pointing it out as a potential issue to be considered. 
In the real world there may be all sorts of correlations that don&#039;t necessarily occur to one when writing queries.
SELECT MIN(OrderDate), MAX(OrderDate)
FROM Orders
WHERE ProductId = @ProductId
It is highly unlikely that productIds will be evenly distributed throughout the Orders table as new products get launched and old ones get discontinued for example.]]></description>
			<content:encoded><![CDATA[<p>Just pointing it out as a potential issue to be considered.<br />
In the real world there may be all sorts of correlations that don&#8217;t necessarily occur to one when writing queries.<br />
SELECT MIN(OrderDate), MAX(OrderDate)<br />
FROM Orders<br />
WHERE ProductId = @ProductId<br />
It is highly unlikely that productIds will be evenly distributed throughout the Orders table as new products get launched and old ones get discontinued for example.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Martin Smith		</title>
		<link>https://lobsterpot.com.au/blog/2012/12/30/the-sql-query-optimizer-when-logical-order-can-get-it-wrong/#comment-2187</link>

		<dc:creator><![CDATA[Martin Smith]]></dc:creator>
		<pubDate>Sun, 30 Dec 2012 16:53:27 +0000</pubDate>
		<guid isPermaLink="false">http://blogs.lobsterpot.com.au/?p=3180#comment-2187</guid>

					<description><![CDATA[Hi Rob,
I&#039;m not saying that the scan plan is definitely worse (at least assuming perfect statistics) just that it can have more variable performance when the rows are not in fact exactly evenly distributed.
Say there are 1,000,000 rows. 1,000 match the seek predicate. Under the even distribution assumption SQL Server will assume that 1,000 (1 million / 1 thousand) rows need to be scanned.
For the seek plan the best, worst, and estimated case are all 1,000 rows
For the scan plan the best, worst, and estimated case are (1, 999,000, 1,000) and if the statistics are not perfect and in fact no rows match at all then the real worst case would be 1 million rows.
If the predicate is made less selective so 10,000 rows now match
For the seek plan the best, worst, and estimated case are all 10,000 rows
For the scan plan the best, worst, and estimated case are (1, 990,000, 100)]]></description>
			<content:encoded><![CDATA[<p>Hi Rob,<br />
I&#8217;m not saying that the scan plan is definitely worse (at least assuming perfect statistics) just that it can have more variable performance when the rows are not in fact exactly evenly distributed.<br />
Say there are 1,000,000 rows. 1,000 match the seek predicate. Under the even distribution assumption SQL Server will assume that 1,000 (1 million / 1 thousand) rows need to be scanned.<br />
For the seek plan the best, worst, and estimated case are all 1,000 rows<br />
For the scan plan the best, worst, and estimated case are (1, 999,000, 1,000) and if the statistics are not perfect and in fact no rows match at all then the real worst case would be 1 million rows.<br />
If the predicate is made less selective so 10,000 rows now match<br />
For the seek plan the best, worst, and estimated case are all 10,000 rows<br />
For the scan plan the best, worst, and estimated case are (1, 990,000, 100)</p>
]]></content:encoded>
		
			</item>
	</channel>
</rss>
