<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblogcasts.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>SQL and the like : order, Optimizer, UDF</title><link>http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/order/Optimizer/UDF/default.aspx</link><description>Tags: order, Optimizer, UDF</description><dc:language>en</dc:language><generator>CommunityServer 2007.1 (Build: 20917.1142)</generator><item><title>SQL 101 : Without “ORDER BY”, order is not guaranteed.</title><link>http://sqlblogcasts.com/blogs/sqlandthelike/archive/2010/06/27/sql-101-without-order-by-order-is-not-guaranteed.aspx</link><pubDate>Sat, 26 Jun 2010 23:16:55 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:14436</guid><dc:creator>Dave Ballantyne</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://sqlblogcasts.com/blogs/sqlandthelike/rsscomments.aspx?PostID=14436</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/sqlandthelike/archive/2010/06/27/sql-101-without-order-by-order-is-not-guaranteed.aspx#comments</comments><description>&lt;font size="3"&gt; &lt;p&gt;It’s as simple as that. If you don’t specify ORDER BY, then the order of your result set is not guaranteed. Oh sure , there may be situations where the data looks like it is being returned ordered, but this is not really the case. So, for example :&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;CREATE TABLE #Example
    &lt;/span&gt;&lt;span style="color:gray;"&gt;(
    row_id  &lt;/span&gt;&lt;span style="color:blue;"&gt;INTEGER
    &lt;/span&gt;&lt;span style="color:gray;"&gt;);
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO    
INSERT  #Example 
select top&lt;/span&gt;&lt;span style="color:gray;"&gt;(10) &lt;/span&gt;&lt;span style="color:magenta;"&gt;ROW_NUMBER&lt;/span&gt;&lt;span style="color:gray;"&gt;() &lt;/span&gt;&lt;span style="color:blue;"&gt;over &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;order by &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;Select &lt;/span&gt;&lt;span style="color:gray;"&gt;null))
&lt;/span&gt;&lt;span style="color:blue;"&gt;from &lt;/span&gt;&lt;span style="color:green;"&gt;syscolumns
&lt;/span&gt;&lt;span style="color:blue;"&gt;go
SELECT  E&lt;/span&gt;&lt;span style="color:gray;"&gt;.row_id
&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM    #Example E&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;p&gt;&lt;/font&gt;&lt;font size="3"&gt;On a number of occasions on different forums, the suggestion has been made that row_id will be in order. Certainly it is here (or if not, let me know ). Is that enough to say &amp;quot;It is in order&amp;quot; ?&lt;/p&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Courier New"&gt;&lt;font color="#0000ff" size="2" face="Courier New"&gt;&lt;font color="#0000ff" size="2" face="Courier New"&gt;&lt;pre class="code"&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="3"&gt;&lt;span style="color:blue;"&gt;insert into #Example&lt;/span&gt;&lt;span style="color:gray;"&gt;(row_id) &lt;/span&gt;&lt;span style="color:blue;"&gt;values&lt;/span&gt;&lt;span style="color:gray;"&gt;(-1)
&lt;/span&gt;&lt;span style="color:blue;"&gt;go
SELECT  E&lt;/span&gt;&lt;span style="color:gray;"&gt;.row_id
&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM    #Example E&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;Now, that’s out of order. Ahh , you may say, &amp;quot;That’s a heap table. A clustered key will define the order. After all, the data is already in that order, so no need for an order by. It’s going to start at row 1 and scan all the way through&amp;quot;. NO, parallelism can cause multiple streams to start at multiple points in the table. Connor Cunningham goes through that scenario &lt;/font&gt;&lt;a href="http://blogs.msdn.com/b/conor_cunningham_msft/archive/2008/08/27/no-seatbelt-expecting-order-without-order-by.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="3"&gt;&lt;font color="#0000ff" size="3"&gt;here&lt;/u&gt;&lt;/font&gt;&lt;/font&gt;&lt;/a&gt;&lt;font size="3"&gt; .&lt;/p&gt;
&lt;p&gt;Ok , what if you have a small number of rows and parallelism is not an issue. Now we don’t need the order by.&lt;/p&gt;
&lt;p&gt;How about this ?&lt;/p&gt;&lt;/font&gt;&lt;font size="3"&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Drop TABLE #Example
go
CREATE TABLE #Example
    &lt;/span&gt;&lt;span style="color:gray;"&gt;(
    row_id  &lt;/span&gt;&lt;span style="color:blue;"&gt;INTEGER primary key&lt;/span&gt;&lt;span style="color:gray;"&gt;,
    uuid    &lt;/span&gt;&lt;span style="color:blue;"&gt;uniqueidentifier &lt;/span&gt;&lt;span style="color:gray;"&gt;not null
    );
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO    
Create unique index idxExample on #Example&lt;/span&gt;&lt;span style="color:gray;"&gt;(uuid)
&lt;/span&gt;&lt;span style="color:blue;"&gt;go

INSERT  #Example 
select top&lt;/span&gt;&lt;span style="color:gray;"&gt;(10) 
       &lt;/span&gt;&lt;span style="color:magenta;"&gt;ROW_NUMBER&lt;/span&gt;&lt;span style="color:gray;"&gt;() &lt;/span&gt;&lt;span style="color:blue;"&gt;over &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;order by &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;Select &lt;/span&gt;&lt;span style="color:gray;"&gt;null)),
       &lt;/span&gt;&lt;span style="color:magenta;"&gt;NEWID&lt;/span&gt;&lt;span style="color:gray;"&gt;()
&lt;/span&gt;&lt;span style="color:blue;"&gt;from &lt;/span&gt;&lt;span style="color:green;"&gt;syscolumns
&lt;/span&gt;&lt;span style="color:blue;"&gt;go
SELECT  &lt;/span&gt;&lt;span style="color:gray;"&gt;*
&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM    #Example E&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;p&gt;That’s going to scan the clustered key , right ? Nope, at least not on my machine.&lt;/p&gt;&lt;/font&gt;&lt;font size="3" face="Calibri"&gt;&lt;font size="3" face="Calibri"&gt;&lt;span&gt;
&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/sqlandthelike/OrderScan_4C49425D.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="OrderScan" border="0" alt="OrderScan" src="http://sqlblogcasts.com/blogs/sqlandthelike/OrderScan_thumb_11EDCC7C.jpg" width="514" height="157" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;font size="3"&gt;&lt;span&gt;
&lt;p&gt;It produces a scan of the NON-clustered index. A discussion of why is not for now, but an illustration of my previous point.&lt;/p&gt;
&lt;p&gt;So , to avoid using ORDER BY , we need: &lt;/p&gt;


&lt;p&gt;A) A non heap table&lt;/p&gt;
&lt;p&gt;B) To avoid parallelism&lt;/p&gt;
&lt;p&gt;C) A clustered index&lt;/p&gt;
&lt;p&gt;D) No non clustered indexes&lt;/p&gt;
&lt;p&gt;During a recent discussion Paul White posted this example&lt;/p&gt;&lt;/font&gt;&lt;font size="3"&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;CREATE TABLE dbo&lt;/span&gt;&lt;span style="color:gray;"&gt;.Example
    (
    row_id  &lt;/span&gt;&lt;span style="color:blue;"&gt;INTEGER IDENTITY &lt;/span&gt;&lt;span style="color:gray;"&gt;NOT NULL &lt;/span&gt;&lt;span style="color:blue;"&gt;PRIMARY KEY CLUSTERED&lt;/span&gt;&lt;span style="color:gray;"&gt;,
    data    &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:magenta;"&gt;CONVERT&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;VARCHAR&lt;/span&gt;&lt;span style="color:gray;"&gt;(11), row_id) &lt;/span&gt;&lt;span style="color:blue;"&gt;PERSISTED &lt;/span&gt;&lt;span style="color:gray;"&gt;NOT NULL &lt;/span&gt;&lt;span style="color:blue;"&gt;UNIQUE
    &lt;/span&gt;&lt;span style="color:gray;"&gt;);
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO    
INSERT  dbo&lt;/span&gt;&lt;span style="color:gray;"&gt;.Example (data)
&lt;/span&gt;&lt;span style="color:blue;"&gt;DEFAULT VALUES&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO 10
SELECT  E&lt;/span&gt;&lt;span style="color:gray;"&gt;.row_id, E.data
&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM    dbo&lt;/span&gt;&lt;span style="color:gray;"&gt;.Example E;
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;p&gt;Again that is now out of order due to the index to maintain the uniqueness on the data column. If I need to add a column like this to a table, the issue of non – ordered data would be low down on my list of thoughts.&lt;/p&gt;
&lt;p&gt;All of these scenarios, you can, perhaps legitimately, argue don’t apply to your system and that you *know* you can meet all of these conditions. Will that always be true? Are you really happy with a table that you can’t add an index to? Even so, the engine may well change in the future and completely destroy your assumption. Then what will happen? Will you be able to confidently find and fix all the statements? That’s a big price to pay to save an extra few keystrokes now.&lt;/p&gt;
&lt;p&gt;Just add ORDER BY now, and sleep safe at night.&lt;/p&gt;&lt;/font&gt;&lt;/span&gt;&lt;font size="3" face="Calibri"&gt;&lt;font size="3" face="Calibri"&gt;&lt;span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=14436" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/TSQL/default.aspx">TSQL</category><category domain="http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/UDF/default.aspx">UDF</category><category domain="http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/Query+Plan/default.aspx">Query Plan</category><category domain="http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/Optimizer/default.aspx">Optimizer</category><category domain="http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/Cache/default.aspx">Cache</category><category domain="http://sqlblogcasts.com/blogs/sqlandthelike/archive/tags/order/default.aspx">order</category></item></channel></rss>