<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	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/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sqlity.net &#187; Performance</title>
	<atom:link href="http://sqlity.net/en/topic/general/performance/feed/" rel="self" type="application/rss+xml" />
	<link>http://sqlity.net/en</link>
	<description>Quality for SQL</description>
	<lastBuildDate>Fri, 18 May 2012 13:05:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>The Mysterious &#8220;sp_&#8221; System Procedure Prefix</title>
		<link>http://sqlity.net/en/961/the-mysterious-sp_-system-procedure-prefix/</link>
		<comments>http://sqlity.net/en/961/the-mysterious-sp_-system-procedure-prefix/#comments</comments>
		<pubDate>Sun, 13 May 2012 21:04:46 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=961</guid>
		<description><![CDATA[<p>
If you have been working with SQL Server for a while you probably know that you should not select names for your stored procedures that start with the three characters "sp_".
</p>
<p>
Today I would like to take a closer look at all the myths and facts around this prefix. All examples in this article have been tested on SQL 2008R2 and on SQL 2012.
</p>
]]></description>
			<content:encoded><![CDATA[<div>
<h3>Introduction</h3>
<p>
If you have been working with SQL Server for a while you probably know that you should not select names for your stored procedures that start with the three characters "sp_".
</p>
<p>
Today I would like to take a closer look at all the myths and facts around this prefix. This will include a series of examples, all of which have been tested on SQL 2008R2 and on SQL 2012.
</p>
<h3>Special Objects</h3>
<p>
The first myth I would like to bust is that the "sp_" prefix stands for "system procedure".
</p>
<p>
While the BOL entry for <a href="http://msdn.microsoft.com/en-us/library/ms190669(v=sql.105).aspx">Creating Stored Procedures</a> uses language that could easily be interpreted like that, it actually never says anything about the etymology of this prefix. In fact, the "sp_" prefix causes a special path to be taken in the resolution of the object name. This works for stored procedures as well as for other object types. Later on this article contains an example with a table.
</p>
<p>
As "sp_" designates more objects than just stored procedures as special, it clearly does not mean "System Procedure", even though it currently is only used for system procedures. Instead it just stands for "special".
</p>
<h3>Resource Database</h3>
<p>
The idea for this article came from a tweet in a discussion about this prefix started by @ericstephani. In the tweet in question @SirSQL suggested to check if <span class="tt">master</span> was indeed the database checked first, as everyone in the discussion had assumed before, or if it rather is the resource database. This makes a lot of sense, as most of the system objects live in the resource database. So I decided to check this out by running a series of tests.
</p>
<p>
If you want to follow along with these tests you will need two databases: One with the name <span class="tt">test</span> and one that is called <span class="tt">OtherDb</span>.
</p>
<p>
For the first test I created a procedure with the name <span class="tt">sp_executesql</span> in <span class="tt">master</span> as well as in <span class="tt">test</span> and then executed it from both places:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
USE master;
GO
CREATE PROCEDURE dbo.sp_executesql
@statement NVARCHAR(MAX)
AS
BEGIN
  SELECT DB_NAME() [called from], 'master' [sp_executesql];
END
GO
EXEC dbo.sp_executesql @statement = N'SELECT DB_NAME() [called from], ''system'' [sp_executesql];';
GO
DROP PROCEDURE dbo.sp_executesql;
GO
------------------------------------------------
GO
USE test;
GO
CREATE PROCEDURE dbo.sp_executesql
@statement NVARCHAR(MAX)
AS
BEGIN
  SELECT DB_NAME() [called from], 'test' [sp_executesql];
END
GO
EXEC dbo.sp_executesql @statement = N'SELECT DB_NAME() [called from], ''system'' [sp_executesql];';
GO
DROP PROCEDURE dbo.sp_executesql;
GO
</pre>
</div>
<p>
The <span class="tt">sp_executesql</span> version that gets shipped with SQL Server lives in the resource database and so we would expect this version to get executed in all cases. This is indeed correct, as you can see in the result:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/05/sp_executesql_test_results.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/05/sp_executesql_test_results.png" alt="sp executesql test results The Mysterious sp  System Procedure Prefix" title="sp_executesql test results" width="194" height="109" class="aligncenter size-full wp-image-965" /></a>
</p>
<p>
The above test shows that the resource database is checked first when an object name with the "sp_" prefix is encountered. That means that if you create any object with that name prefix you are running the risk that it will not be accessible anymore after the next service pack install if Microsoft decided to create an object with the same name in the resource database. This is even true when the resource database object is of a different type than your object. This you can quickly confirm by creating a table with the name <span class="tt">sp_executesql</span> in any database and trying to insert a row into it.
</p>
<h3>Master Piece</h3>
<p>
The fact that the resource database is the one checked first to resolve "sp_" object names raises the question where the <span class="tt">master</span> database fits in. Read on, as the results might surprise you.
</p>
<p>
The second test involves a procedure that is not (yet) part of the resource database: <span class="tt">sp_MyOwnProc</span>
</p>
<p>
I again created this procedure in <span class="tt">master</span> and in <span class="tt">test</span>:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
GO
USE master;
GO
CREATE PROCEDURE sp_MyOwnProc
AS
BEGIN
  SELECT DB_NAME() [called from], 'master' [sp_MyOwnProc];
END
GO
USE test;
GO
CREATE PROCEDURE sp_MyOwnProc
AS
BEGIN
  SELECT DB_NAME() [called from], 'test' [sp_MyOwnProc];
END
GO
EXEC sp_MyOwnProc;
GO
USE OtherDb;
GO
EXEC sp_MyOwnProc;
GO
USE test;
GO
DROP PROCEDURE sp_MyOwnProc;
GO
USE master;
GO
DROP PROCEDURE sp_MyOwnProc;
GO
</pre>
</div>
<p>
The above code creates the procedure in both places. It then executes the <span class="tt">EXEC sp_MyOwnProc;</span> statement, first from the <span class="tt">test</span> database and afterwards from the <span class="tt">OtherDb</span> database. The result is shown below:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/05/sp_MyOwnProc_test_results.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/05/sp_MyOwnProc_test_results.png" alt="sp MyOwnProc test results The Mysterious sp  System Procedure Prefix" title="sp_MyOwnProc test results" width="200" height="108" class="aligncenter size-full wp-image-966" /></a>
</p>
<p>
As you can see, <span class="tt">master</span> is not checked first for an "sp_" object. Instead the object in the current database is used. Only if the current database does not contain the object in question <span class="tt">master</span> is looked at to see if the object exists in there.
</p>
<p>
The same behavior can be observed when all references to the <span class="tt">sp_MyOwnProc</span> in the above script are schema-qualified with <span class="tt">dbo.</span>
</p>
<h3>Other Object Types</h3>
<p>
You also get the same behavior if you go through this exercise with a table:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
USE master;
GO
CREATE TABLE sp_MyOwnTable(
sp_MyOwnTable NVARCHAR(MAX)
);
INSERT INTO sp_MyOwnTable SELECT DB_NAME();
GO
USE test;
GO
CREATE TABLE sp_MyOwnTable(
sp_MyOwnTable NVARCHAR(MAX)
);
INSERT INTO sp_MyOwnTable SELECT DB_NAME();
GO
SELECT DB_NAME() [called from], * FROM sp_MyOwnTable;
GO
USE OtherDb;
GO
SELECT DB_NAME() [called from], * FROM sp_MyOwnTable;
GO
USE test;
GO
DROP TABLE sp_MyOwnTable;
GO
USE master;
GO
DROP TABLE sp_MyOwnTable;
GO
</pre>
</div>
<p>
This script creates a table with the name <span class="tt">sp_MyOwnTable</span> in the <span class="tt">master</span> as well as in the <span class="tt">test</span> database and then executes a select against this name executing in <span class="tt">test</span> as well as in <span class="tt">OtherDb</span>. The result is shown here:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/05/sp_MyOwnTable_test_reults.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/05/sp_MyOwnTable_test_reults.png" alt="sp MyOwnTable test reults The Mysterious sp  System Procedure Prefix" title="sp_MyOwnTable test reults" width="206" height="108" class="aligncenter size-full wp-image-967" /></a>
</p>
<p>
This shows that the name resolution works the same for tables as it does for stored procedures. It also works views, but not for functions or user defined types.
</p>
<h3>Performance Impact</h3>
<p>
Now we know that SQL Server tries to find an "sp_" object in the resource database first and only if it does not exist there the search is continued in the current database. So there should be a measurable performance impact showing this extra work.
</p>
<p>
To measure the impact I used this script:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
USE test;
GO
IF OBJECT_ID('dbo.sp_MyOwnProc2') IS NOT NULL DROP PROCEDURE dbo.sp_MyOwnProc2;
GO
CREATE PROCEDURE dbo.sp_MyOwnProc2
AS
RETURN 0;
GO
IF OBJECT_ID('dbo.MyOwnProc2') IS NOT NULL DROP PROCEDURE dbo.MyOwnProc2;
GO
CREATE PROCEDURE dbo.MyOwnProc2
AS
RETURN 0;
GO
------------------------------------
GO
DECLARE @StartTime DATETIME2 = SYSDATETIME();
DECLARE @EndTime DATETIME2 = SYSDATETIME();
DECLARE @Counter INT = 0;
DECLARE @CmdA NVARCHAR(100) = 'EXEC dbo.MyOwnProc2;--';
DECLARE @CmdB NVARCHAR(100) = 'EXEC dbo.sp_MyOwnProc2;--';
DECLARE @TimeA BIGINT=0;
DECLARE @TimeB BIGINT=0;
DECLARE @Cmd2 NVARCHAR(100);
WHILE(@Counter&lt;10000000)
BEGIN
  SET @Cmd2 = @CmdA + CAST(@Counter AS NVARCHAR(20));
  SET @StartTime = SYSDATETIME();
  EXEC(@Cmd2);
  SET @EndTime = SYSDATETIME();
  SET @TimeA += DATEDIFF(microsecond,@StartTime,@EndTime)
  SET @Cmd2 = @CmdB + CAST(@Counter AS NVARCHAR(20));
  SET @StartTime = SYSDATETIME();
  EXEC(@Cmd2);
  SET @EndTime = SYSDATETIME();
  SET @TimeB += DATEDIFF(microsecond,@StartTime,@EndTime)
  SET @Counter += 1;
END
SELECT @Counter Counter,@TimeA [MyOwnProc2], @TimeB [sp_MyOwnProc2];
GO
</pre>
</div>
<p>
It first creates two identical stored procedures that do nothing but return a 0. The first one is called <span class="tt">sp_MyOwnProc2</span>, the second one carries the name <span class="tt">MyOwnProc2</span> without the "sp_" prefix. To measure the performance impact, the script calls both procedures alternating in a loop and records their execution times. Each call gets executed as dynamic sql with the current loop count being part of the sql string. This prevents any possible attempts to cache the plan for the batch. It does however not prevent caching the plan for the procedure itself. That is okay, as we are after the name resolution piece of the execution. Because both procedures get called alternatingly, any background noise caused by other processes on the test system should affect both evenly.  
</p>
<p>
On my system I got these results:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/05/sp_prefix_performance_test_results.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/05/sp_prefix_performance_test_results.png" alt="sp prefix performance test results The Mysterious sp  System Procedure Prefix" title="sp_ prefix performance test results" width="283" height="63" class="aligncenter size-full wp-image-968" /></a>
</p>
<p>
After 10 million executions of each of the two procedures you can see, that there is a performance impact. With less than 2 percent, however, it is very small compared to the time it takes to just call the procedure. Remember, that the procedures in this test did not actually do any work, so all the time recorded by this test was spent on identifying the procedure and the overhead of calling it.
</p>
<h3>Conclusion</h3>
<p>
The "sp_" object name prefix causes SQL Server to take a special route when resolving the name of this object: First SQL Server checks if the object exists in the hidden resource database. Second it tries to find the object in the current database and if it does not exist there SQL Server goes on to check if the object exists in the <span class="tt">master</span> database.
</p>
<p>
If you name your own objects using this prefix, you have to be aware of two possible consequences:
First there is a small but measurable impact on performance. Second it can cause your application to suddenly break, if Microsoft decides to add an object with the same name to the resource database.
</p>
<p>
Because of that it is a best practice to not use the "sp_" name prefix anywhere in your code. 
</p>
<p>
There is one exception however: If you are creating an object that you want to be accessible from all databases, you can use this prefix and place the object in the <span class="tt">master</span> database. However, because of the database precedence there are now two possibilities for those objects to get eclipsed by another object. So, if you go this route, make sure to regularly check that the object you are trying to execute is actually the one executing.
</p>
</div>
<div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F961%2Fthe-mysterious-sp_-system-procedure-prefix%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/961/the-mysterious-sp_-system-procedure-prefix/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/961/the-mysterious-sp_-system-procedure-prefix/"  data-text="The Mysterious &#8220;sp_&#8221; System Procedure Prefix" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/961/the-mysterious-sp_-system-procedure-prefix/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/961/the-mysterious-sp_-system-procedure-prefix/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tracing the Actual Execution Plan for a single Query</title>
		<link>http://sqlity.net/en/952/tracing-the-actual-execution-plan-for-a-single-query/</link>
		<comments>http://sqlity.net/en/952/tracing-the-actual-execution-plan-for-a-single-query/#comments</comments>
		<pubDate>Sat, 05 May 2012 21:18:30 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=952</guid>
		<description><![CDATA[SQL Server offers several ways to get to the execution plan for a particular query. Most of them however only provide the estimated execution plan without actual counts and statistics. In this article we are going to look at a way to get to the actual execution plan of a particular query using a trace.]]></description>
			<content:encoded><![CDATA[<div>
<h3>Introduction</h3>
<p>
SQL Server offers several ways to get to the execution plan for a particular query. Most of them however only provide the estimated execution plan without actual counts and statistics. In this article we are going to look at a way to get to the actual execution plan of a particular query.
</p>
<h3>Tracing</h3>
<p>
The certainly easiest way to get the actual plan of a query is to actually execute it in SSMS while the "collect actual execution plan" option is turned on. However, sometimes you want to collect the actual execution plan for a query every time it gets executed in your production environment. The only way to do this in SQL Server 2008R2 and earlier was to run a trace and collect the "Showplan XML Statistics Profile" event.
</p>
<p>
The problem with this approach is that it is not trivial to restrict the collected information to execution plans of one query. That means that on a busy system thousands of these events will fire in a very short time. With the included XML execution plan the amount of data to be collected will be quickly overloading most production systems.
</p>
<h3>Filtering Options</h3>
<p>
If the statement you are interested in is inside of a stored procedure you are somewhat in luck, as it is simple to filter by the name of the procedure which is returned by the event in the ObjectName column.
</p>
<p>
However, if the statement is an ad hoc or a prepared statement, this simple option does not exist anymore. There are a few other columns you can filter by like the login name, but most of the time you won't have the option to single out a specific query to use different connection settings.
</p>
<p>
The next option would be to filter on the text of the query. However, the query text is unfortunately not included in this event &ndash; neither as separate column nor within the execution plan XML.
That leaves only one column that we can try to filter on, the execution plan itself.
</p>
<p>
While the execution plan is stripped of most of the query text, there are two types of names that are included in the execution plan: Parameter names and table alias names. Parameter names are only included if the statement is a prepared statement. Table alias names will be included in all types of statements that access a table. Be aware, that column alias names are not included in the execution plan. 
</p>
<h3>Random Alias</h3>
While most often the table alias names are not unique between all the queries in a system, it is usually not too difficult to change a particular query to use some distinct character string as an alias name for one table. A change like that will not modify the query behavior nor will it influence the plan choice of the optimizer but it will us something to filter by.
</p>
<p>
The easiest way to come up with such an identifying name is to just use a random character string like "ir83n476s9d". Make sure however that the name of your choice begins with a letter. It also should not contain any special characters.
</p>
<p>
Once your query is prepared like this, you can easily restrict a "Showplan XML Statistics Profile" trace to only include this query by using a "Like" filter on the TextData column and setting it to "%ir83n476s9d%".
</p>
<h3>Conclusion</h3>
<p>
This simple trick allows you to filter the "Showplan XML Statistics Profile" event in a trace to fire only for a particular query. While it is not always possible to change a query to accommodate this, in many cases it is easy to do.
</p>
<p>
On final word of caution: When running traces in a production environment you should never use the SQL Profiler, especially when dealing with high-volume events like the "Showplan XML Statistics Profile" event. Instead setup your trace as a server-side trace to write the collected data to a fast, preferably dedicated drive. That way the performance impact on the system will be kept as small as possible.
</p>
</div>
<div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F952%2Ftracing-the-actual-execution-plan-for-a-single-query%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/952/tracing-the-actual-execution-plan-for-a-single-query/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/952/tracing-the-actual-execution-plan-for-a-single-query/"  data-text="Tracing the Actual Execution Plan for a single Query" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/952/tracing-the-actual-execution-plan-for-a-single-query/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/952/tracing-the-actual-execution-plan-for-a-single-query/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Unloved Backward Scan</title>
		<link>http://sqlity.net/en/930/the-unloved-backward-scan/</link>
		<comments>http://sqlity.net/en/930/the-unloved-backward-scan/#comments</comments>
		<pubDate>Sun, 29 Apr 2012 20:31:29 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=930</guid>
		<description><![CDATA[<p>
When a query requires rows to be sorted, either directly requested with an [tt]ORDER BY[/tt] clause or because one of the iterators requires it, SQL Server has two options to guarantee that order. The obvious one is to utilize a sort iterator. If the data comes from an index (clustered or covering), SQL Server can also use an "Ordered Scan" of the data. Depending on the requested sort direction, such an ordered scan can be either forward or backward.
</p>
<p>
This would hardly be worth an article, if there wasn't the peculiarity that SQL Server obviously does not like the idea of having to execute an ordered scan that is directed backwards.
</p>]]></description>
			<content:encoded><![CDATA[<div>
<h3>Introduction</h3>
<p>
When a query requires rows to be sorted, either directly requested with an <span class="tt">ORDER BY</span> clause or because one of the iterators requires it, SQL Server has two options to guarantee that order. The obvious one is to utilize a sort iterator. If the data comes from an index (clustered or covering), SQL Server can also use an "Ordered Scan" of the data. Depending on the requested sort direction, such an ordered scan can be either forward or backward.
</p>
<p>
This would hardly be worth an article, if there wasn't the peculiarity that SQL Server obviously does not like the idea of having to execute an ordered scan that is directed backwards.
</p>
<h3>Backward Scan Dislike</h3>
<p>
Let's look at an example. First we need some tables with data:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
IF OBJECT_ID('dbo.T1') IS NOT NULL DROP TABLE dbo.T1;
IF OBJECT_ID('dbo.T2') IS NOT NULL DROP TABLE dbo.T2;

CREATE TABLE dbo.T1(
Id INT CONSTRAINT T1_PK PRIMARY KEY CLUSTERED,
v1 INT,
c1 VARCHAR(8000)
);

CREATE TABLE dbo.T2(
Id INT CONSTRAINT T2_PK PRIMARY KEY CLUSTERED,
v1 INT,
c1 VARCHAR(8000)
);

INSERT INTO dbo.T1(Id,v1,c1)
SELECT n,CHECKSUM(NEWID()),'*'
FROM dbo.GetNums(1000000);

INSERT INTO dbo.T2(Id,v1,c1)
SELECT n,CHECKSUM(NEWID()),'*'
FROM dbo.GetNums(1000000);
--Get dbo.GetNums here: http://www.sqlmag.com/article/sql-server/virtual-auxiliary-table-of-numbers 
</pre>
</div>
<p>
This script is creating two tables containing one million rows each. The v1 column is filled with random values; the c1 column just contains a single constant character. The Id column is the clustered primary key and it is providing the ordering on disk that we are going to use.
</p>
<p>
The query is a little made up. It joins T2 to itself bringing back only one set of columns. It also restricts the result of this join to the first one million rows, sorted by T2.Id. The one million values in T2.v1 are random from a set of 4 billion making them "mostly" unique. That means the self-join is expected to return about one million rows anyway. Those rows are then joined to T1. In the end the <span class="tt">ORDER BY</span> requests that all rows be returned sorted by the Id column of the T1 table:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  *
FROM    dbo.T1 A
        INNER JOIN ( SELECT TOP ( 1000000 )
                            B.*
                     FROM   dbo.T2 B
                            INNER JOIN dbo.T2 C ON B.v1 = C.v1
                     ORDER BY B.Id
                   ) BC ON A.Id = BC.Id
ORDER BY A.Id;
</pre>
</div>
<p>
The execution plan of this query looks like this:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Plan_with_Forward_Scan.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Plan_with_Forward_Scan.png" alt="Plan with Forward Scan The Unloved Backward Scan" title="Plan with Forward Scan" width="1123" height="248" class="aligncenter size-full wp-image-937" /></a>
</p>
<p>
There is nothing unexpected in this plan. The T2 self-join is done with a hash join operator, as there is no index on the v1 column. The data is then sorted by a sort operator and passed through a serial zone for the top operator. After that there is no additional sort operator for the data to pass through. As the merge join requires both streams to be sorted the same way on the join column, this means that the data must be produced sorted by the scan of the T1 table. A quick look at its properties confirms that:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Forward_Scan_Iterator_Properties.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Forward_Scan_Iterator_Properties.png" alt="Forward Scan Iterator Properties The Unloved Backward Scan" title="Forward Scan Iterator Properties" width="263" height="389" class="aligncenter size-full wp-image-934" /></a>
</p>
<p>
This scan is a forward scan, as both <span class="tt">ORDER BY</span> statements  are asking to sort by Id ascending. To make this scan go backwards we should just have to change the query to sort by Id descending in both places:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  *
FROM    dbo.T1 A
        INNER JOIN ( SELECT TOP ( 1000000 )
                            B.*
                     FROM   dbo.T2 B
                            INNER JOIN dbo.T2 C ON B.v1 = C.v1
                     ORDER BY B.Id DESC
                   ) BC ON A.Id = BC.Id
ORDER BY A.Id DESC;
</pre>
</div>
<p>
 However, this query produces this rather unexpected plan:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Backwards_Scan_avoidance_with_Loop_Join.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Backwards_Scan_avoidance_with_Loop_Join.png" alt="Backwards Scan avoidance with Loop Join The Unloved Backward Scan" title="Backward Scan avoidance with Loop Join" width="1110" height="164" class="aligncenter size-full wp-image-933" /></a>
</p>
<p>
A loop join with an index seek against the T1 table to retrieve 1,000,000 single rows &ndash; that cannot be good.
</p>
<p>
Before we look at execution statistics let's force the merge join back by specifying a join hint:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  *
FROM    dbo.T1 A
        INNER MERGE JOIN ( SELECT TOP ( 1000000 )
                                  B.*
                           FROM   dbo.T2 B
                                  INNER JOIN dbo.T2 C ON B.v1 = C.v1
                           ORDER BY B.Id DESC
                         ) BC ON A.Id = BC.Id
ORDER BY A.Id DESC;
</pre>
</div>
<p>
 Now we get the expected plan again:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Merge_Join_encouraged_Backward_Scan.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Merge_Join_encouraged_Backward_Scan.png" alt="Merge Join encouraged Backward Scan The Unloved Backward Scan" title="Merge Join encouraged Backward Scan" width="1117" height="250" class="aligncenter size-full wp-image-936" /></a>
</p>
<p>
If you compare the properties for the iterators in the forward scan and the backward scan plan you will notice, that the cost of the two scan directions is not that much different:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Backward_Scan_Iterator_properties.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Backward_Scan_Iterator_properties.png" alt="Backward Scan Iterator properties The Unloved Backward Scan" title="Backward Scan Iterator Properties" width="1082" height="572" class="aligncenter size-full wp-image-932" /></a>
</p>
<p>
The estimated cost of the scan iterator is 0% in both cases. The bulk of the work is done in the hash self-join and the following sort of the T2 table.
</p>
<p>
So, let us take a look at the execution statistics of all three queries:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Query_Execution_Statistics.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Query_Execution_Statistics.png" alt="Query Execution Statistics The Unloved Backward Scan" title="Query Execution Statistics" width="656" height="77" class="aligncenter size-full wp-image-938" /></a>
</p>
<p>
The execution statistics clearly show that the decision to go with a loop join was not necessarily the best. While the estimated cost for the backward scan is about 150% of the estimated cost for the loop join, the actual reads for the loop join version are about 3 million, which is more than 250 times higher than the 8000 reads for either scan direction.
</p>
<h3>Disk Access</h3>
<p>
To understand were this dislike is coming from we need to look at the access pattern necessary to retrieve the data from disk. A forward scan of a table (or index), that is not heavily fragmented, looks pretty much like doing a single contiguous read of a big blob of data. SQL Server has a lot of performance optimizations build in that make this type of access as fast as possible. The Read-Ahead mechanism is a good example for that.
</p>
<p>
A backward scan on the other hand looks quite the opposite: After reading a page, the disk has to do almost a complete turn to get to the previous page, which is the next one in line to be read. This is about the worst kind of random access you can come by. 
</p>
<p>
As SQL Server always assumes that none of the requested pages are in cache, the decision to not get into that backward spinning game seems quite understandable. 
</p>
<p>
Also, if you closely compare the two "scanning" execution plans you will notice that while the forward scan iterator is parallelized, the backward scan operator is executed single threaded. This is a general rule: SQL Server cannot execute a backward scan in parallel. That makes sense as with all that waiting for the disk to do another spin to get to the "next" page, it is unlikely for the data to come in quickly enough to keep multiple threads busy.
</p>
<h3>Estimates?</h3>
<p>
But wait, there is one more thing: If you look at the image above and compare the properties of all iterators in the two scanning plans, you will notice something odd. The estimated CPU cost of the "hash match inner join" iterator goes from 11 in the "forward" case to 1357 in the "backward" case; the estimated IO cost makes a similar jump from 0 to 1654. That seems to not make a lot of sense, as the next iterator, the sort, is a blocking iterator. "Blocking" means that the iterator reads in <u>all</u> input rows into a holding area before producing any output rows. This implies that anything on the left side of a sort should not be able to influence the cost of operators on the right side of it. That is, unless it affects the number of rows significantly, as this is a TOP N Sort. See <a href="http://sqlity.net/en/908/top-n-sort-a-little-bit-of-sorting/"> TOP N Sort – A Little Bit of Sorting </a> for an explanation. But as in this example all columns are "mostly" unique, the optimizer guesses correctly that about one million rows get passed into the hash join on each input and also about one million rows come out the other end. So row count estimates should not matter here. 
</p>
<p>
If you look at the estimates when executing just that inner query sorting backwards, you will see that they exactly match the ones in the imbedded forward sorting case:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Iterator_Properties_for_Inner_Select.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Iterator_Properties_for_Inner_Select.png" alt="Iterator Properties for Inner Select The Unloved Backward Scan" title="Iterator Properties for Inner Select" width="994" height="353" class="aligncenter size-full wp-image-935" /></a>
</p>
<p>
That means that the scan direction change of the T1 table causes the estimates on the other side of the merge join to get completely thrown off. 
</p>
<h3>Conclusion</h3>
<p>
SQL Servers dislike of backward scan operations is understandable when looking at the work necessary to retrieve the records from disk in opposite index order. Additionally, a backward scan cannot be executed in parallel. That adds to the list of reasons, why the backward scan seems unloved. 
</p>
<p>
However, the main reason why SQL Server avoids backward scans seems to be that they throw its cost estimations off, making following iterators appear a lot more expensive than they really are.
</p>
</div>
<div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F930%2Fthe-unloved-backward-scan%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/930/the-unloved-backward-scan/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/930/the-unloved-backward-scan/"  data-text="The Unloved Backward Scan" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/930/the-unloved-backward-scan/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/930/the-unloved-backward-scan/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TOP N Sort &#8211; A Little Bit of Sorting</title>
		<link>http://sqlity.net/en/908/top-n-sort-a-little-bit-of-sorting/</link>
		<comments>http://sqlity.net/en/908/top-n-sort-a-little-bit-of-sorting/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 00:39:06 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=908</guid>
		<description><![CDATA[Sorting is one of the most often used functions in SQL Server. It is used when creating indexes. It allows us to retrieve data in a particular order. It also is used to filter out repeated rows in the context of a DISTINCT request. The SQL Server Team spent a lot of effort optimizing the sort algorithms to give the best possible performance in each context. This blog post looks at the TOP N Sort optimization.]]></description>
			<content:encoded><![CDATA[<div>
<h3>Introduction</h3>
<p>
Sorting is one of the most often used functions in SQL Server. It is used when creating indexes. It allows us to retrieve data in a particular order. It also is used to filter out repeated rows in the context of a <span class="tt">DISTINCT</span> request. The SQL Server Team spent a lot of effort optimizing the sort algorithms to give the best possible performance in each context. They even implemented sort avoidance where the expensive sort gets removed from the query plan if it is known that the input is sorted already or will contain only a single distinct value. 
</p>
<p>
One of those optimizations is the TOP N Sort that I would like to look at in a little more detail today.
</p>
<h3>Memory Requirements for Sorting</h3>
<p>
Sorting requires memory &ndash; potentially a lot of memory. SQL Server estimates the size of the data using statistics and data size estimates and then requests about 150 percent of that in memory for the sort operation.
</p>
<p>To see how much memory a query is using, you can use the <span class="tt">sys.dm_exec_query_memory_grants</span> DMV. It shows the current memory usage for each SPID that requested additional memory for one (or more) of the memory consuming operators.
</p>
<p>
The problem with this DMV is that its values change quickly, so it is difficult to get meaningful information for a particular query. There is however a trick you can use: Every memory consuming iterator has a build phase where most of the memory is used, and a delivery phase in which the rows get send to the parent operator. The memory consumption during the build phase is usually a lot higher. SQL Server recognizes this and reuses the additional memory during the delivery phase for other memory consuming iterators.
</p>
<p>
The <span class="tt">sys.dm_exec_query_memory_grants</span> DMV contains the columns <span class="tt">used_memory_kb</span> and columns <span class="tt">max_used_memory_kb</span> that report current and maximum memory usage. If we can ensure that we get the data from this DMV during the delivery phase of the operator in question, the max_used_memory_kb column will tell us exactly how much memory was used during the build phase. This however only works for queries with a single memory consuming operator that also needs to be blocking.
</p>
<p>
Sort is a blocking operator. That means that during the build phase no rows get transmitted. If we include the request for the memory data in the query and place it before ("left of" in the graphical plan) the sort, we know that the sort will have finished its build phase when the data gets retrieved from the DMV.
</p>
<p>
Let us look at an example:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
IF OBJECT_ID('dbo.FixedWidth') IS NOT NULL DROP TABLE dbo.FixedWidth;

CREATE TABLE dbo.FixedWidth(
Id INT PRIMARY KEY CLUSTERED,
c1 INT NOT NULL,
fill VARCHAR(1000) NOT NULL
);

INSERT INTO dbo.FixedWidth(Id,c1,fill)
SELECT n,CHECKSUM(NEWID()),REPLICATE('X',192)
FROM dbo.GetNums(10000);

SELECT SUM(DATALENGTH(Id)+DATALENGTH(c1)+DATALENGTH(fill))
FROM dbo.FixedWidth;
 </pre>
</div>
<p>
This snippet creates the table dbo.FixedWidth and inserts 10000 rows into it. It then sums up the DATALENGTH of all columns over all rows.  The size of all the data totals 2,000,000 bytes. It is using <a href="http://www.sqlmag.com/article/sql-server/virtual-auxiliary-table-of-numbers">Itzik Ben-Gan's GetNums function</a>.
</p>
<p>
The following query will sort the data in this table and report its memory usage:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  ( SELECT  *
          FROM    sys.dm_exec_query_memory_grants
          WHERE   session_id = @@SPID
        FOR
          XML PATH('') ,
              TYPE
        ) Mem ,
        *
FROM    dbo.FixedWidth
ORDER BY c1;
</pre>
</div>
<p>
This query has below execution plan:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Query_with_realtime_sys.dm_exec_query_memory_grants_Access.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Query_with_realtime_sys.dm_exec_query_memory_grants_Access.png" alt="Query with realtime sys.dm exec query memory grants Access TOP N Sort   A Little Bit of Sorting" title="Query with real time access to sys.dm_exec_query_memory_grants" width="1284" height="285" class="aligncenter size-full wp-image-910" /></a>
</p>
<p>
The access to the <span class="tt">sys.dm_exec_query_memory_grants</span> DMV happens after the sort has finished. Therefore the <span class="tt">max_used_memory_kb</span> will tell us the amount actually used for the sort of the entire 2MB table. The information from the memory DMV is returned as a single XML value. As the DMV result is spooled in this query, all rows will show the same XML value:
</p>
<div>
<pre class="brush: xml; title: ; notranslate">
&lt;session_id&gt;66&lt;/session_id&gt;
&lt;request_id&gt;0&lt;/request_id&gt;
&lt;scheduler_id&gt;1&lt;/scheduler_id&gt;
&lt;dop&gt;1&lt;/dop&gt;
&lt;request_time&gt;2012-04-22T19:09:40.303&lt;/request_time&gt;
&lt;grant_time&gt;2012-04-22T19:09:40.307&lt;/grant_time&gt;
&lt;requested_memory_kb&gt;7352&lt;/requested_memory_kb&gt;
&lt;granted_memory_kb&gt;7352&lt;/granted_memory_kb&gt;
&lt;required_memory_kb&gt;512&lt;/required_memory_kb&gt;
&lt;used_memory_kb&gt;2456&lt;/used_memory_kb&gt;
&lt;max_used_memory_kb&gt;2456&lt;/max_used_memory_kb&gt;
&lt;query_cost&gt;3.460044653270174e+000&lt;/query_cost&gt;
&lt;timeout_sec&gt;86&lt;/timeout_sec&gt;
&lt;resource_semaphore_id&gt;0&lt;/resource_semaphore_id&gt;
&lt;plan_handle&gt;BgA6AB2ceA5AIZDfAAAAAAAAAAAAAAAA&lt;/plan_handle&gt;
&lt;sql_handle&gt;AgAAAB2ceA7MMroMHW//TQYN1cSbf5KW&lt;/sql_handle&gt;
&lt;group_id&gt;2&lt;/group_id&gt;
&lt;pool_id&gt;2&lt;/pool_id&gt;
&lt;is_small&gt;0&lt;/is_small&gt;
&lt;ideal_memory_kb&gt;7352&lt;/ideal_memory_kb&gt; 
</pre>
</div>
<p>
It shows that 7,352KB is the ideal memory grant size the optimizer came up with. This was also the amount that was granted. However, only 2,456KB where actually used during the sort.
</p>
<h3>TOP N Sort</h3>
<p>
If you are interested only in the first few rows based on a sort order, you do not need to complete sort the rest of the rows.
To find the top most row it is enough to take the first row of the data set and compare it to each remaining row, keeping each time the one row that comes first according to the sort order. If you have more than one row you can follow the same principle, you just have to keep the first n rows after each step. 
</p>
<p>
SQL Server implements this with the TOP N Sort operator:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT TOP ( 10 )
        *
FROM    dbo.FixedWidth
ORDER BY c1; 
</pre>
</div>
<p>
This simple query has the following execution plan:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/04/Query_with_TOP_N_Sort.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/04/Query_with_TOP_N_Sort.png" alt="Query with TOP N Sort TOP N Sort   A Little Bit of Sorting" title="Query with TOP N Sort" width="504" height="112" class="aligncenter size-full wp-image-911" /></a>
</p>
<p>
As you can see, the sort operator is of type "TOP N Sort".
</p>
<p>
You can use the same trick as shown above to get its memory consumption, but you have to add an outer layer, otherwise SQL Server removes the TOP N Sort optimization:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  ( SELECT  *
          FROM    sys.dm_exec_query_memory_grants
          WHERE   session_id = @@SPID
        FOR
          XML PATH('') ,
              TYPE
        ) Mem ,
        *
FROM    ( SELECT TOP ( 10 )
                  *
          FROM    dbo.FixedWidth
          ORDER BY c1
        ) X;
</pre>
</div>
<div>
<pre class="brush: xml; title: ; notranslate">
&lt;session_id&gt;66&lt;/session_id&gt;
&lt;request_id&gt;0&lt;/request_id&gt;
&lt;scheduler_id&gt;1&lt;/scheduler_id&gt;
&lt;dop&gt;1&lt;/dop&gt;
&lt;request_time&gt;2012-04-22T19:25:18.023&lt;/request_time&gt;
&lt;grant_time&gt;2012-04-22T19:25:18.023&lt;/grant_time&gt;
&lt;requested_memory_kb&gt;1024&lt;/requested_memory_kb&gt;
&lt;granted_memory_kb&gt;1024&lt;/granted_memory_kb&gt;
&lt;required_memory_kb&gt;24&lt;/required_memory_kb&gt;
&lt;used_memory_kb&gt;24&lt;/used_memory_kb&gt;
&lt;max_used_memory_kb&gt;24&lt;/max_used_memory_kb&gt;
&lt;query_cost&gt;8.388694532701750e-001&lt;/query_cost&gt;
&lt;timeout_sec&gt;25&lt;/timeout_sec&gt;
&lt;resource_semaphore_id&gt;1&lt;/resource_semaphore_id&gt;
&lt;plan_handle&gt;BgA6AM04yitAYc7jAAAAAAAAAAAAAAAA&lt;/plan_handle&gt;
&lt;sql_handle&gt;AgAAAM04yivnP5lrZVMtEy5tLK/6dHjX&lt;/sql_handle&gt;
&lt;group_id&gt;2&lt;/group_id&gt;
&lt;pool_id&gt;2&lt;/pool_id&gt;
&lt;is_small&gt;1&lt;/is_small&gt;
&lt;ideal_memory_kb&gt;32&lt;/ideal_memory_kb&gt; 
</pre>
</div>
<p>
This query used only 24KB, clearly not enough to hold the entire table, so the TOP N Sort optimization was used. 
</p>
<p>
The algorithms SQL Server uses for sorting are not documented. However, it is clear that an algorithm to find the TOP N rows cannot be as efficient as a normal sort when sorting the same number of rows. For that reason there is a maximum number of rows for which SQL Server uses the TOP N Sort optimization. That number was set to 100.
</p>
<p>
If you run above query with TOP(100) you will get a memory usage of 128KB:
</p>
<div>
<pre class="brush: xml; title: ; notranslate">
&lt;session_id&gt;66&lt;/session_id&gt;
&lt;request_id&gt;0&lt;/request_id&gt;
&lt;scheduler_id&gt;1&lt;/scheduler_id&gt;
&lt;dop&gt;1&lt;/dop&gt;
&lt;request_time&gt;2012-04-22T19:32:38.127&lt;/request_time&gt;
&lt;grant_time&gt;2012-04-22T19:32:38.127&lt;/grant_time&gt;
&lt;requested_memory_kb&gt;1024&lt;/requested_memory_kb&gt;
&lt;granted_memory_kb&gt;1024&lt;/granted_memory_kb&gt;
&lt;required_memory_kb&gt;128&lt;/required_memory_kb&gt;
&lt;used_memory_kb&gt;128&lt;/used_memory_kb&gt;
&lt;max_used_memory_kb&gt;128&lt;/max_used_memory_kb&gt;
&lt;query_cost&gt;8.624926532701749e-001&lt;/query_cost&gt;
&lt;timeout_sec&gt;25&lt;/timeout_sec&gt;
&lt;resource_semaphore_id&gt;1&lt;/resource_semaphore_id&gt;
&lt;plan_handle&gt;BgA6AKCsNDBAIVXkAAAAAAAAAAAAAAAA&lt;/plan_handle&gt;
&lt;sql_handle&gt;AgAAAKCsNDB6vVhQtTSg6/3xIflWWU1M&lt;/sql_handle&gt;
&lt;group_id&gt;2&lt;/group_id&gt;
&lt;pool_id&gt;2&lt;/pool_id&gt;
&lt;is_small&gt;1&lt;/is_small&gt;
&lt;ideal_memory_kb&gt;136&lt;/ideal_memory_kb&gt; 
</pre>
</div>
<p>
 If you use TOP(101) the memory usage goes up to 2,456KB:
</p>
<div>
<pre class="brush: xml; title: ; notranslate">
&lt;session_id&gt;66&lt;/session_id&gt;
&lt;request_id&gt;0&lt;/request_id&gt;
&lt;scheduler_id&gt;1&lt;/scheduler_id&gt;
&lt;dop&gt;1&lt;/dop&gt;
&lt;request_time&gt;2012-04-22T19:32:11.993&lt;/request_time&gt;
&lt;grant_time&gt;2012-04-22T19:32:11.993&lt;/grant_time&gt;
&lt;requested_memory_kb&gt;7352&lt;/requested_memory_kb&gt;
&lt;granted_memory_kb&gt;7352&lt;/granted_memory_kb&gt;
&lt;required_memory_kb&gt;512&lt;/required_memory_kb&gt;
&lt;used_memory_kb&gt;2456&lt;/used_memory_kb&gt;
&lt;max_used_memory_kb&gt;2456&lt;/max_used_memory_kb&gt;
&lt;query_cost&gt;8.627551332701751e-001&lt;/query_cost&gt;
&lt;timeout_sec&gt;25&lt;/timeout_sec&gt;
&lt;resource_semaphore_id&gt;0&lt;/resource_semaphore_id&gt;
&lt;plan_handle&gt;BgA6AMCfYwlA4WnkAAAAAAAAAAAAAAAA&lt;/plan_handle&gt;
&lt;sql_handle&gt;AgAAAMCfYwlb3oB4gW5K1oLplwLKxsA+&lt;/sql_handle&gt;
&lt;group_id&gt;2&lt;/group_id&gt;
&lt;pool_id&gt;2&lt;/pool_id&gt;
&lt;is_small&gt;0&lt;/is_small&gt;
&lt;ideal_memory_kb&gt;7352&lt;/ideal_memory_kb&gt; 
</pre>
</div>
<p>
All the memory numbers match the ones from the whole table sort, so SQL Server decided to execute a standard sort followed by a standard TOP operation instead of using the TOP N Sort optimization.
</p>
<p>
This boundary is fixed and cannot be configured. There is also no hint to force this optimization. That is rather unfortunate as 100 seems to be a quite arbitrary boundary value and a TOP N Sort would often perform a lot better that a full table sort followed by a TOP.
</p>
<h3>Conclusion</h3>
<p>
We all know that while the optimizer in general is very good a finding a (close to) optimal plan, sometimes it does not. 
</p>
<p>
The TOP N Sort optimization is a great enhancement, if you are dealing with 100 or less rows. However at 101 rows you will see a sudden drop in performance. To deal with this, you can either restrict the value of rows to return to 100, if the business allows. Or you can help SQL Server to deal with the "all rows" sort. One of the most obvious options here is to add an index to the table.
</p>
</div>
<div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F908%2Ftop-n-sort-a-little-bit-of-sorting%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/908/top-n-sort-a-little-bit-of-sorting/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/908/top-n-sort-a-little-bit-of-sorting/"  data-text="TOP N Sort &#8211; A Little Bit of Sorting" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/908/top-n-sort-a-little-bit-of-sorting/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/908/top-n-sort-a-little-bit-of-sorting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimizer, what if I had more CPUs?</title>
		<link>http://sqlity.net/en/828/optimizer-what-if-i-had-more-cpus/</link>
		<comments>http://sqlity.net/en/828/optimizer-what-if-i-had-more-cpus/#comments</comments>
		<pubDate>Tue, 27 Mar 2012 14:00:45 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=828</guid>
		<description><![CDATA[In the March issue of SQL Server Pro Itzik Ben-Gan wrote about an undocumented DBCC command that was recently discovered in the wild by Eladio Rincon (http://www.sqlmag.com/article/sql-server/options-affecting-parallelism-141505). Itzik closed the article by expressing his hope to get this statement documented as it can be very helpfull to database professionals trying to performance tune a query <a href="http://sqlity.net/en/828/optimizer-what-if-i-had-more-cpus/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
In the March issue of SQL Server Pro Itzik Ben-Gan wrote about an undocumented DBCC command that was recently discovered in the wild by Eladio Rincon (<a href="http://www.sqlmag.com/article/sql-server/options-affecting-parallelism-141505" target="_blank">http://www.sqlmag.com/article/sql-server/options-affecting-parallelism-141505</a>). 
Itzik closed the article by expressing his hope to get this statement documented as it can be very helpfull to database professionals trying to performance tune
a query on a none production system, that does not completely match the production environment.
</p>
<p>
I agree with this opinion, and so I decided to spend some time investigating this functionality further.
<p>
<h3>Optimizer_WhatIf?</h3>
<p>
The DBCC command is the OPTIMIZER_WHATIF cammand. DBCC HELP gives you the following information about it:
</p>
<p>
<pre>
dbcc OPTIMIZER_WHATIF ({property/cost_number | property_name} [, {integer_value | string_value} ])
</pre>
</p>
<p>
This is &ndash; according to Google &ndash; the only publicly available information about this command. Eladio discovered it in use at a customer site. 
The customer was told by Microsoft that with the first parameter equal to one, the second would influence parallelism decisions of the optimizer. 
</p>
<p>
After reading Itziks article it seemed clear that the "1" meant "number of schedulers" or "number of CPUs". 
The above documentation snippet says that you can either specify a number or a name for the first parameter, so knowing the possible non-numeric values
for it would be a start in understanding what else this command does.
</p>
<h3>Finding Strings</h3>
<p>
Every windows programm has to somehow contain the strings it is using. SQL Server is no exception. A well designed program will have related strings close by each other.
</p>
<p>
You can use a program like <a href="http://technet.microsoft.com/en-us/sysinternals/bb896653" target="_blank">Mark Russinovich's Process Explorer</a>
to get a list of all strings in the memory space of a running process. 
</p>
<p>
As all statements (including DBCC commands) are strings, you can expect to find the possible values for the first parameter next to each other. With that thought in mind I went ahead and 
searched for strings containing "CPU" or "scheduler". I found this list of possible property_name values for SQL Server 2008 and SQL Server 2008 R2:
<pre>
Status
ResetAll
CPUs
MemoryMBs
Bits
ParallelCardThreshold
ParallelCostThreshold
ParallelCardCrossProd
</pre>
In SQL Server 2012 these properties were added.
<pre>
LowCEThresholdFactorBy10
HighCEThresholdFactorBy10
CEThresholdFactorCrossover
DMLChangeThreshold
</pre>
DBCC OPTIMIZER_WHATIF was available in SQL Server 2005 as well, but "ResetAll" and "Status" are not working, so I did not investigate further.
</p>
<h5>Warning</h5>
<p>
All property names are case sensitive, even in a case insensitive installation! You also will not get an error message if an invalid name or value is passed in, so be careful.
</p>
<h3>Many More CPUs</h3>
<p>
The third one, "CPUs" causes the functionality described by Itzik: If you run 
<pre>DBCC OPTIMIZER_WHATIF(CPUs, 16) WITH NO_INFOMSGS;</pre>
the optimizer will subsequently optimizer all statements submitted in the same session as if the system had 16 CPUs.
</p>
<h3>Administrative Help</h3>
<p>
If you run
<pre>DBCC OPTIMIZER_WHATIF(ResetAll) WITH NO_INFOMSGS;</pre>
all changes caused by this DBCC command to the current session are undone.
</p>
<p>
<pre>DBCC OPTIMIZER_WHATIF(Status) WITH NO_INFOMSGS;</pre>
finally gives you the currently set values and their defaults. It also returns the integer representation of each property:
<pre>
---------------------------------------------------------

Optimizer what-if status

---------------------------------------------------------

property_number current_value default_value property_name

---------------------------------------------------------

         1                  0             0 CPUs

         2                  0             0 MemoryMBs

         3                  0             0 Bits

         4               1000          1000 ParallelCardThreshold

         5                  1             1 ParallelCostThreshold

         6                200           200 ParallelCardCrossProd

         7                 50            50 LowCEThresholdFactorBy10

         8                 12            12 HighCEThresholdFactorBy10

         9             100000        100000 CEThresholdFactorCrossover

        10                 10            10 DMLChangeThreshold
</pre>
(As with all undocumented DBCC commands, you first need to run "DBCC TRACEON (3604) WITH NO_INFOMSGS;" in your session to get any output.)
</p>
<h3>Conclusion</h3>
<p>
This DBCC command is a great tool, when you are trying to answer questions like: What if the optimizer had more (or less) CPUs available than there are in my current system.
</p>
<p>
As with all undocumented functionality however, don't use this in production unless advised to do so by Microsoft support.
</p>
<p>
This post covered only three of the possible values for the first parameter. The other ones will be addressed in future posts.
</p>
</div><div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F828%2Foptimizer-what-if-i-had-more-cpus%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/828/optimizer-what-if-i-had-more-cpus/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/828/optimizer-what-if-i-had-more-cpus/"  data-text="Optimizer, what if I had more CPUs?" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/828/optimizer-what-if-i-had-more-cpus/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/828/optimizer-what-if-i-had-more-cpus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Key Lookup Operator in Update Statements</title>
		<link>http://sqlity.net/en/810/key-lookup-operator-in-update-statements/</link>
		<comments>http://sqlity.net/en/810/key-lookup-operator-in-update-statements/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 14:00:39 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=810</guid>
		<description><![CDATA[When thinking about the indexes for update statements it is easy to overlook an important peculiarity in the way SQL Server finds the rows to update before updating them. Those pesky Lookups If you have an UPDATE statement that filters on two columns and you have an index on one of them, you might be <a href="http://sqlity.net/en/810/key-lookup-operator-in-update-statements/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
When thinking about the indexes for update statements it is easy to overlook an important peculiarity in the way SQL Server finds the rows to update before updating them.
</p>
<h3>Those pesky Lookups</h3>
<p>
If you have an UPDATE statement that filters on two columns and you have an index on one of them, you might be tempted to think that the necessary lookup for the second column is not going to cost a lot - particular when that second column is not selective at all - as SQL Server has to access the storage place of each row anyway when executing the actual update. This however is not true, as SQL Server executes the update in two separate phases: One to identify the rows and one to update those rows. That means a lookup in the find phase can be very expensive.
</p>
<p>
Let us look at an example. Use the following script to create two identical tables and insert 200,000 rows into each of them.
</p>
<div>
<pre class="brush: sql; title: ; notranslate">

CREATE TABLE dbo.tst1(
 Id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
 Val INT,
 Filter INT,
 IdxKey INT,
 Fill CHAR(1000) DEFAULT 'Fill'
);

CREATE TABLE dbo.tst2(
 Id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
 Val INT,
 Filter INT,
 IdxKey INT,
 Fill CHAR(1000) DEFAULT 'Fill'
);

INSERT INTO dbo.tst1(Val,Filter,IdxKey)
OUTPUT INSERTED.Val,INSERTED.Filter,INSERTED.IdxKey INTO dbo.tst2(Val,Filter,IdxKey)
SELECT 0,0, n%1000
FROM dbo.GetNums(200000);
</pre>
</div>
<p>
The Filter column will be used to force the lookup later on by adding "Filter = 0" to the where clause. It is valued 0 in all rows, so no row will be excluded by this filter.
</p>
<p>
After creating the tables, create the following indexes:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
CREATE INDEX dbo_tst1_IdxKey ON dbo.tst1(IdxKey);
CREATE INDEX dbo_tst2_IdxKey ON dbo.tst2(IdxKey) INCLUDE (Filter);
</pre>
</div>
<p>
Both indexes are on the IdxKey column, but the index on the dbo.tst2 table also includes the Filter column.
</p>
<p>
Now run the following two identical update statements against the two tables:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
UPDATE dbo.tst1
  SET Val = 17
WHERE IdxKey &lt;30 AND Filter = 0;

UPDATE dbo.tst2
  SET Val = 17
WHERE IdxKey &lt;30 AND Filter = 0;
</pre>
</div>
<p>
The first one requires a lookup operator as the Filter column is not included in the index on dbo.tst1. Below are the two execution plans:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/update_with_bookmark_lookup.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/update_with_bookmark_lookup.png" alt="update with bookmark lookup Key Lookup Operator in Update Statements" title="Update with Bookmark Lookup" width="1451" height="275" class="aligncenter size-full wp-image-813" /></a>
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/update_without_bookmark_lookup.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/update_without_bookmark_lookup.png" alt="update without bookmark lookup Key Lookup Operator in Update Statements" title="Update without Bookmark Lookup" width="1210" height="131" class="aligncenter size-full wp-image-812" /></a>
</p>
<p>
As you can clearly see, the update operator is separated from the data retrieval operator(s) by several other operators. It looks like all the filtering and value preparations happen before the update operator which is then just updating all rows passed to it without any further filtering.
</p>
<h3>Statistics</h3>
<p>
I ran the above statements in a loop, each executing 2000 times and recorded time and logical reads. The averaged results are below:
</p>
<p>
<table>
  <thead>
    <tr>
      <th class="cpu_time-cell">cpu_time</th>
      <th class="total_elapsed_time-cell">total_elapsed_time</th>
      <th class="logical_reads-cell">logical_reads</th>
      <th class="exec_count-cell">exec_count</th>
      <th class="Cmd-cell">command</th>
    </tr>
  </thead>
  <tbody>
    <tr class="firstRow">
      <td class="cpu_time-cell">98</td>
      <td class="total_elapsed_time-cell">175</td>
      <td class="logical_reads-cell">37212</td>
      <td class="exec_count-cell">2000</td>
      <td class="Cmd-cell">  UPDATE dbo.tst1    SET Val = 17  WHERE IdxKey <30 AND Filter = 0;  </td>
    </tr>
    <tr class="lastRow">
      <td class="cpu_time-cell">47</td>
      <td class="total_elapsed_time-cell">72</td>
      <td class="logical_reads-cell">19211</td>
      <td class="exec_count-cell">2000</td>
      <td class="Cmd-cell">  UPDATE dbo.tst2    SET Val = 17  WHERE IdxKey <30 AND Filter = 0;  </td>
    </tr>
  </tbody>
</table>
</p>
<p>
The cpu time, the elapsed time and the logical reads were each about twice as high in the query against dbo.tst1, the one requiring the lookup operator. This was the case even though the lookup did not actually filter any rows - every row accessed by the lookup had to be updated as well.
</p>
<h3>Conclusion</h3>
<p>
The above statistics prove what the execution plan already suggested: The finding of rows for an update and the update itself are separate steps in SQL Server update queries. That means the "find" portion has to be optimized as if it were a standalone SELECT. In particular, lookup operations can not be ignored as SQL Server accesses the rows twice in this case: Once for the lookup and once for the update.
</p>
</div><div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F810%2Fkey-lookup-operator-in-update-statements%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/810/key-lookup-operator-in-update-statements/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/810/key-lookup-operator-in-update-statements/"  data-text="Key Lookup Operator in Update Statements" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/810/key-lookup-operator-in-update-statements/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/810/key-lookup-operator-in-update-statements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Story of the Evil Assert Operator</title>
		<link>http://sqlity.net/en/735/the-story-of-the-evil-assert-operator/</link>
		<comments>http://sqlity.net/en/735/the-story-of-the-evil-assert-operator/#comments</comments>
		<pubDate>Tue, 06 Mar 2012 15:00:24 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=735</guid>
		<description><![CDATA[Today I am going to talk about the evil side of the Assert Operator. To start out, let me introduce this operator to you: The Assert Operator The Assert Operator is used by SQL Server in execution plans that require some condition to be satisfied to be valid. A common scenario in which an Assert <a href="http://sqlity.net/en/735/the-story-of-the-evil-assert-operator/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
Today I am going to talk about the evil side of the Assert Operator. To start out, let me introduce this operator to you: 
</p>
<h3> The Assert Operator</h3>
<p>
The Assert Operator is used by SQL Server in execution plans that require some condition to be satisfied to be valid.
A common scenario in which an Assert Operator is used is an insert into a table that has a check constraint defined. Take for example the dbo.TableWithCheckConstraint table:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
CREATE TABLE dbo.TableWithCheckConstraint(
  Id INT PRIMARY KEY CLUSTERED,
  Even INT CONSTRAINT TableWithCheckConstraint_Even_Check CHECK (Even % 2 = 0)
);
</pre>
</div>
<p>
If you run this simple insert against that table
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
INSERT INTO dbo.TableWithCheckConstraint(Id,Even)
SELECT n, 2*n FROM (VALUES(1),(2))X(n);
</pre>
</div>
<p>
you will get an execution plan that looks like this:
</p>
<div style="clear:both;">
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/ExecutionPlan_for_insert_with_Check_Constraint.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/ExecutionPlan_for_insert_with_Check_Constraint.png" alt="ExecutionPlan for insert with Check Constraint The Story of the Evil Assert Operator" title="Execution plan for insert with Check Constraint" width="870" height="109" class="aligncenter size-full wp-image-737" /></a>
</p>
</div>
<p>
The properties of the highlighted Assert Operator are shown below:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/properties_of_the_check_constraint_assert.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/properties_of_the_check_constraint_assert.png" alt="properties of the check constraint assert The Story of the Evil Assert Operator" title="Properties of the Check Constraint Assert" width="780" height="415" class="aligncenter size-full wp-image-739" /></a>
</p>
<p>
Asserts in general are very cheap operators as you can see when you look at the Estimated Operator Cost in above image. An Assert operator works by calculating a given expression. If that expression results in anything other than NULL, the assert fails and stops the execution of the current statement. The expression in above example is the formula we used for the check constraint itself, wrapped in a case statement to return either NULL or 0.
</p>
<h3>The Dark Side of the Assert</h3>
<p>
So, how can such an innocent little operator be evil? 
</p>
<p>
Sometimes SQL Server requires a certain condition to be satisfied in situations where you do not necessarily expect it. The most common example is a sub-query in the column list or the WHERE clause of a select statement as shown in the following example:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  ( SELECT  m
          FROM    (VALUES (1), (2) ) X(m)
        );
</pre>
</div>
<p>
If you execute this query you get this error:
</p>
<p>
<pre>
Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
</pre>
</p>
<p>
To enforce that rule, SQL Server is using an Assert Operator again:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/assert_operator_in_select_statement.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/assert_operator_in_select_statement.png" alt="assert operator in select statement The Story of the Evil Assert Operator" title="Assert Operator in Select Statement" width="633" height="110" class="aligncenter size-full wp-image-742" /></a>
</p>
<p>
In above example the Stream Aggregate Operator is tasked with counting the rows returned: 
<pre>[Expr1005] = Scalar Operator(Count(*))</pre>
The Assert then makes sure that this count is at max one with the following predicate:
<pre>CASE WHEN [Expr1005]>(1) THEN (0) ELSE NULL END</pre>
</p>
<p>
(If you look more closely you will find that the Stream Aggregate actually calculates two aggregates in this query and that the second one is of a surprising type. Check out <a href="http://sqlblog.com/blogs/paul_white/archive/2011/07/02/undocumented-query-plans-the-any-aggregate.aspx" title="The ANY Aggregate" target="_blank">this article by Paul White</a> for an explanation.)
</p>
<p>
In this example the Stream Aggregate and the Assert make up together 50% of the (estimated) query cost, but as this is a very made-up example I would not pay to much attention to that. So let us look at a real life example. 
</p>
<h3>The Forgotten Uniqueness</h3>
<p>
First we need a few tables:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
CREATE TABLE dbo.AssertBigFact(
 Id INT PRIMARY KEY CLUSTERED,
 Sort1 INT UNIQUE,
 Luv INT,
 Data CHAR(1000)
);

DECLARE @BigSize INT = 1000000;
DECLARE @LookupSize INT = 1000;

INSERT INTO dbo.AssertBigFact(Id,Sort1,Luv,Data)
SELECT n,(n*1123)%@BigSize+1,n%@LookupSize+1,'' FROM dbo.GetNums(@BigSize)


CREATE TABLE dbo.AssertLookupNonUnique(
 Id INT ,
 Val INT
);
CREATE CLUSTERED INDEX AssertLookupNonUnique_CI ON dbo.AssertLookupNonUnique(Id);

CREATE TABLE dbo.AssertLookupUnique(
 Id INT ,
 Val INT
);
CREATE UNIQUE CLUSTERED INDEX AssertLookupUnique_CI ON dbo.AssertLookupUnique(Id);

INSERT 
  INTO dbo.AssertLookupNonUnique(Id,Val)
OUTPUT INSERTED.Id,INSERTED.Val
  INTO dbo.AssertLookupUnique(Id,Val)
SELECT n,n%37 FROM dbo.GetNums(@LookupSize);
</pre>
</div>
<p>
As most of my examples, this one is also using Itzik's GetNums function that you can get here: <a href="http://www.sqlmag.com/article/sql-server/virtual-auxiliary-table-of-numbers" title="Virtual Auxiliary Table of Numbers" target="_blank">Virtual Auxiliary Table of Numbers</a>.
</p>
<p>
It creates three tables, the table dbo.AssertBigFact that contains 1,000,000 rows and the two small 1,000 row lookup tables dbo.AssertLookupUnique and dbo.AssertLookupNonUnique. The insert statement uses the OUTPUT clause to insert the same rows in both tables, so with the exception of the clustered index on the dbo.AssertLookupNonUnique table that got "accidentally" not declared as unique, these two tables are identical.
</p>
<p>
Now let us compare the following two almost identical queries. They only differ in the lookup table they go against.
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO
SELECT b.*,(SELECT Val FROM dbo.AssertLookupNonUnique l WHERE l.Id = b.Luv) Val
FROM dbo.AssertBigFact b
ORDER BY b.Sort1,Val;
GO
SELECT b.*,(SELECT Val FROM dbo.AssertLookupUnique l WHERE l.Id = b.Luv) Val
FROM dbo.AssertBigFact b
ORDER BY b.Sort1,Val;
GO
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;
</pre>
</div>
<p>
The execution plans for above queries look like this: 
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/execution_plan_for_two_lookup_queries.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/execution_plan_for_two_lookup_queries.png" alt="execution plan for two lookup queries The Story of the Evil Assert Operator" title="Execution Plan for the two Lookup Queries" width="1370" height="423" class="aligncenter size-full wp-image-746" /></a>
</p>
<p>
The top version, going against the non-unique table, requires the use of an Assert Operator. The second query on the other end can get away without in, as SQL Server knows that the sub-query can return only a single row because the Id column was declared unique in the definition of the clustered index.
</p>
<p>
In a scenario like this where a rather large table gets joined with a small table, using a hash join is usually the fastest way for SQL Server to execute the query. A hash join requires the entire first table to be stored in a hash table in memory before any row can be returned. A hash can spill to tempdb if there is not enough free memory available, but such a spill is expensive. So hash joins are perfect in a scenario where one of the two join partners is small.
<p>
<p>
In our case SQL Server chose the hash join for the second query, as expected. However the first query uses a loop join. The reason for this is quite simple: SQL Server does not know that the Id column in the dbo.AssertLookupNonUnique table is unique, so it needs to assert that for each Luv value in the dbo.AssertBigFact table there is only one row in the dbo.AssertLookupNonUnique table with a matching Id value. For that it needs to read the dbo.AssertBigFact table first, as there might be id values in the dbo.AssertLookupNonUnique table that do not have a matching Luv value in the dbo.AssertBigFact table. If those Id values were duplicated it would not matter for this query, so the Assert can run only against Id values with a matching Luv value. That however means, that SQL Server can't build the hash table first, at least not with the small dbo.AssertLookupNonUnique table. But it doesn't make sense to build the hash table using the dbo.AssertBigFact table as that would take to much time and memory and would therefore be rather ineffective.
</p>
<p>
A merge join is not a good choice either, as it requires both inputs to be sorted on the join column which is not the case. SQL Server could insert a sort before the join, but that would mean that the full one million rows had to be sorted twice as a different sort order is requested by the query &ndash; a scenario worth avoiding.
</p>
<p>
That means that SQL Server has to use the loop join algorithm. That means it has to assert that there is only a single row in the dbo.AssertLookupNonUnique for each row in the dbo.AssertBigFact table which in turn means that the Stream Aggregate and Assert Operator pair gets executed 1,000,000 times. While each execution is small and cheap, doing a million of them is not. But this is not even the worst problem with this query.
</p>
<h3>Wasted Logical Reads</h3>
<p>
If we look at the logical reads (returned by the SET STATISTICS IO ON statement in above batch) for the query against the dbo.AssertLookupUnique we get these numbers:
</p>
<p>
<pre>
Table 'AssertLookupUnique'. Scan count 3, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'AssertBigFact'. Scan count 3, logical reads 143712, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
</pre>
</p>
<p>
The dbo.AssertLookupUnique has 3 pages as a quick check against sys.dm_db_index_physical_stats confirms:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  OBJECT_SCHEMA_NAME(i.object_id) + '.' + OBJECT_NAME(i.object_id) Tbl ,
        i.name ,
        ips.index_depth ,
        ips.page_count
FROM    sys.indexes i
        JOIN sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) ips 
        ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE   i.index_id &lt; 2
        AND i.object_id IN ( OBJECT_ID('dbo.AssertLookupNonUnique'),
                             OBJECT_ID('dbo.AssertLookupUnique'),
                             OBJECT_ID('dbo.AssertBigFact') );
</pre>
</div>
<p>
This query returns these numbers:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/assert_tables_page_count.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/assert_tables_page_count.png" alt="assert tables page count The Story of the Evil Assert Operator" title="Assert Tables - Page Count" width="526" height="77" class="aligncenter size-full wp-image-772" /></a>
</p>
<p>
The 10 logical reads are caused by the parallelism of this query. The different threads of a single query often read pages that another thread has looked at before. The same behavior you can see with the dbo.AssertBigFact table where also a few of the 142858 pages got read more than once. 
</p>
<p>
If we now look at the numbers for the query against the dbo.AssertLookupNonUnique table we get a quite different picture:
</p>
<p>
<pre>
Table 'AssertLookupNonUnique'. Scan count 1000000, logical reads 2004000, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'AssertBigFact'. Scan count 3, logical reads 143760, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
</pre>
</p>
<p>
While the number of reads against the dbo.AssertBigFact table is about the same as before, there are over 2 million logical reads recorded for the dbo.AssertLookupNonUnique table. &mdash; What a difference...
</p>
<p>
The seek against the dbo.AssertLookupNonUnique was executed one million times, once for each row in the dbo.AssertBigFact table. As the index depth is 2 levels, each seek had to look at two pages &ndash; two million in total.
</p>
<h3>Conclusion</h3>
<p>
As you have seen in the above example, requiring an assert can be quite expensive. While the Assert Operator is not that expensive in it self, SQL Server is severely restricted in the plan choices it can make when an assert is logically required.
</p>
<p>
To avoid situations like this you should always try to give the Optimizer as much information as possible. That includes keeping statistics up to date and using proper indexes. But, as this article has shown, creating an index on the right columns is not necessarily enough. So, if you have an index on a column with unique values, make sure to declare it as unique.
</p>
</div><div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F735%2Fthe-story-of-the-evil-assert-operator%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/735/the-story-of-the-evil-assert-operator/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/735/the-story-of-the-evil-assert-operator/"  data-text="The Story of the Evil Assert Operator" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/735/the-story-of-the-evil-assert-operator/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/735/the-story-of-the-evil-assert-operator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why CXPACKET Waits are not your Performance Problem</title>
		<link>http://sqlity.net/en/708/why-cxpacket-waits-are-not-your-performance-problem/</link>
		<comments>http://sqlity.net/en/708/why-cxpacket-waits-are-not-your-performance-problem/#comments</comments>
		<pubDate>Tue, 28 Feb 2012 15:00:13 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=708</guid>
		<description><![CDATA[There is a lot of information out there recommending to do this or that to deal with the performance problems that you must have if you see CXPACKET waits. All these recommendations build on the notion that the CXPACKET wait is a bad thing. Today I am going to explain why this is not the case. <a href="http://sqlity.net/en/708/why-cxpacket-waits-are-not-your-performance-problem/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
There is a lot of information out there recommending to do this or that to deal with the performance problems that you must have if you see CXPACKET waits.

All these recommendations build on the notion that the CXPACKET wait is a bad thing. Today I am going to explain why this is not the case. I am going to show you that the CXPACKETs are just one part of how the SQL Server engine works and that they do not indicate any problem.
</p>
<h3>Parallel Processing</h3>
<p>
First we need to dive into, how parallel processing of requests in SQL Server works. Every time SQL Server executes a query it does so using its execution plan. You can think of an execution plan as the compiled executable for the query. In this post I am not going to explain how SQL Server produces this plan, but if you want more detail I can recommend the book <a title="&quot;Inside the SQL Server Query Optimizer&quot; at amazon.com" href="http://www.amazon.com/gp/product/1906434603/ref=as_li_ss_tl?ie=UTF8&amp;tag=sqlitynet-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1906434603" target="_blank">Inside the SQL Server Query Optimizer</a> by Benjamin Nevarez (<a title="www.benjaminnevarez.com" href="http://www.benjaminnevarez.com/" target="_blank">blog</a>|<a title="@BenjaminNevarez" href="https://twitter.com/#!/benjaminnevarez" target="_blank">twitter</a>).
</p>
<p>
Under specific circumstances SQL Server can decide to produce  a parallel plan. You can recognize a parallel plan by the yellow circles with two arrows on them that show up on some of the icons in the graphical plan:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/02/Parallel_Plan.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/Parallel_Plan.png" alt="Parallel Plan Why CXPACKET Waits are not your Performance Problem" title="A Parallel SQL Server Execution Plan" width="1338" height="110" class="alignleft size-full wp-image-711" /></a>
</p>
<p>
You will also find at least one of the parallelism iterators:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/02/Parallelism_Operators.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/Parallelism_Operators.png" alt="Parallelism Operators Why CXPACKET Waits are not your Performance Problem" title="The three SQL Server Parallelism Operators" width="139" height="44" class="alignleft size-full wp-image-713" /></a>
</p>
<p>
They are called "Gather Streams", "Repartition Streams" and "Distribute Steams", and as they are always executed in parallel mode, they always appear with the yellow circle on them. 
</p>
<p>
A parallelism iterator acts as thread control point. It takes a request from one ore more threads and passes it on, again to one ore more new threads. When the data is coming back, the iterator collects it and distributes it to the requesting threads. I am again not going to go into the details here. A good explanation can be found in Paul Whites(<a title="sqlblog.com/blogs/paul_white/" href="http://sqlblog.com/blogs/paul_white/" target="_blank">blog</a>|<a title="@SQL_Kiwi" href="https://twitter.com/#!/SQL_Kiwi" target="_blank">twitter</a>) article on simple talk: <a href="http://www.simple-talk.com/sql/learn-sql-server/understanding-and-using-parallelism-in-sql-server/" title="Understanding and Using Parallelism in SQL Server" target="_blank">Understanding and Using Parallelism in SQL Server</a> 
</p>
<p>
I would like to call your attention to the word "new" in the above paragraph. Each icon in an execution plan represents an iterator and execution always starts with the left most iterator. It is the "SELECT" iterator in the above example. Each iterator requests rows from it's direct child iterators and then does some work with those rows. When a parallelism iterator is invoked it spawns n new threads and passes control to all of them. The number n is based on the type of the parallelism iterator and the current Degree Of Parallelism settings. 
</p>
<p>
The original threads, after passing control to the newly spawned threads wait to receive rows back. This waiting is not done by spinning or polling. Instead the thread(s) enter a wait state and wake bake up once a row is available for processing. This allows the processor to be used for other worker threads.
</p>
<p>
The wait type that SQL Server reports for those threads waiting at a parallelism iterator is - you guessed it - the CXPACKET wait.
</p>
<h3>An Example</h3>
<p>
Let's look at an example:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
IF OBJECT_ID('dbo.t1') IS NOT NULL 
  DROP TABLE dbo.t1 ;

CREATE TABLE dbo.t1
  (
    i INT ,
    t TEXT ,
    c1 INT DEFAULT CHECKSUM(NEWID()) ,
    c2 INT DEFAULT CHECKSUM(NEWID())
  ) ;

INSERT  INTO dbo.t1
        ( i ,
          t
        )
        SELECT  n ,
                REPLICATE('X', 200 + ( CHECKSUM(NEWID()) % 10 ))
        FROM    dbo.GetNums(1000000) ;
</pre>
</div>
<p>
This creates the table "t1" and fills it with 1.000.000 strings of random length between 200 and 210 characters. The code uses <a href="http://www.sqlmag.com/article/sql-server/virtual-auxiliary-table-of-numbers" title="dbo.GetNum function by Itzik Ben-Gan">Itzik Ben-Gan's GetNum function</a>
to quickly create the one million rows.
</p>
<p>
Now run this select statement against that table:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT ln, COUNT(1) cnt FROM(SELECT LEN(CAST(t AS NVARCHAR(MAX))) ln FROM dbo.t1) X GROUP BY ln;
</pre>
</div>
<p>
Let's call this the "Count Query". It has the execution plan that was introduced earlier.
</p>
<p>
While this query runs, execute the following "Monitor Query" in a new window. Make sure to change the session_id variable to the SPID of the window executing the Count Query.
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
DECLARE @session_id INT = 75;
SELECT  t.task_address ,
        t.task_state ,
        t.session_id ,
        t.exec_context_id ,
        wt.wait_duration_ms ,
        wt.wait_type ,
        wt.blocking_session_id ,
        wt.blocking_exec_context_id ,
        wt.resource_description ,
        t.scheduler_id
FROM    sys.dm_os_tasks t
        LEFT JOIN sys.dm_os_waiting_tasks wt ON t.task_address = wt.waiting_task_address
WHERE   t.session_id = @session_id
ORDER BY t.exec_context_id,wt.blocking_exec_context_id;
</pre>
</div>
<p>
This query returns one row for every worker thread currently assigned to this query. A thread that is currently blocked might get more than one row, if it is blocked by more than one other thread. For each waiting thread it also shows what it is waiting for.
After about 10 seconds of execution of the Count Query, the Monitor Query returned this result on my machine:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/02/Waiting_Tasks.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/Waiting_Tasks.png" alt="Waiting Tasks Why CXPACKET Waits are not your Performance Problem" title="Waiting Tasks of the Count Query" width="1306" height="153" class="alignleft size-full wp-image-720" /></a>
</p>
<p>
As you can see, there are five different execution_context_ids. Each thread on a parallel query gets its own execution context. The first one, the thread the the query execution started on has always the id 0. The other ones get increasing consecutive numbers. 
</p>
<p>
Thread 0 in above query covers everything up to the "gather Streams" iterator. From there to the "Repartition Streams" iterator threads 1 and 2 get to work in parallel. After that up on to the table scans the query is executed by threads 3 and 4. Those two are busily shoveling rows into the Hash iterator. Because a Hash is a blocking iterator (see <a href="http://blogs.msdn.com/b/craigfr/archive/2006/06/19/637048.aspx" title="Properties of Iterators" target="_blank">Properties of Iterators</a> by Craig Freedman(<a title="blogs.msdn.com/b/craigfr/" href="http://blogs.msdn.com/b/craigfr/" target="_blank">blog</a>) for an explanation of this term), it will not produce any rows until it has consumed all incoming rows. This takes a little over 12 seconds on my machine. During this time the threads 0,1 and 2 are suspended, not taking up any processor resources and therefore not hurting any other thread or query. But they each crank up close to 12 seconds of CXPACKET wait time, for a total of 36 seconds. 
</p>
<h3>Conclusion</h3>
<p>
The above example showed that any parallel query will show potentially very high CXPACKET waits. This is not an indication of a problem, but rather it is an indication that SQL Server is doing it's job properly, making sure that threads that do not have anything to do at the moment make room for other threads on the processors. So, if your system shows high CXPACKET waits, the only conclusion you can draw from that is, that it is using parallelism and that SQL Server's multitasking system is working as designed.
</p>
<p>
However, as the sys.dm_exec_requests (as well as the compatibility view sysprocesses) show only the wait type of thread 0, CXPACKET waits can potentially hide a real problem. If you know that you have a problem, use appropriate techniques to narrow down the source. If you don't know if you have a problem, CXPACKET will not help you to change that.
</p>
<p>
That means, that in almost all situations it is safe to ignore CXPACKET waits. I therefore recommend to add it to the list of waits to ignore in your monitoring queries.
</p>
</div><div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F708%2Fwhy-cxpacket-waits-are-not-your-performance-problem%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/708/why-cxpacket-waits-are-not-your-performance-problem/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/708/why-cxpacket-waits-are-not-your-performance-problem/"  data-text="Why CXPACKET Waits are not your Performance Problem" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/708/why-cxpacket-waits-are-not-your-performance-problem/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/708/why-cxpacket-waits-are-not-your-performance-problem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Purge Problems [TSQL Tuesday #027 - The Big Data Valentine’s Edition]</title>
		<link>http://sqlity.net/en/666/purge-problems-tsql-tuesday-027-the-big-data-valentines-edition/</link>
		<comments>http://sqlity.net/en/666/purge-problems-tsql-tuesday-027-the-big-data-valentines-edition/#comments</comments>
		<pubDate>Tue, 14 Feb 2012 15:00:40 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[T-SQL Tuesday]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=666</guid>
		<description><![CDATA[T-SQL Tuesday #27 is hosted by Steve Jones (blog&#124;twitter). This month’s topic is “Big Data”. Purge Problems in Big Data &#8211; Not only a SELECT needs an index Recently I was called to an issue at a 5+ TB customer. The purge job had stopped working a while back and the disk drives started to <a href="http://sqlity.net/en/666/purge-problems-tsql-tuesday-027-the-big-data-valentines-edition/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
<!--
p {margin-top:8px;}
-->
</style>
<div>
<p><a href="https://voiceofthedba.wordpress.com/2012/02/07/t-sql-tuesday-027-the-big-data-valentines-edition/"><img height="132" border="0" hspace="9" width="131" alt="SqlTuesday Purge Problems [TSQL Tuesday #027   The Big Data Valentine’s Edition]" src="http://images.sqlity.net/SqlTuesday.png" title="Purge Problems [TSQL Tuesday #027   The Big Data Valentine’s Edition]" /></a></p>
<p>T-SQL Tuesday #27 is hosted by Steve Jones (<a href="https://voiceofthedba.wordpress.com/">blog</a>|<a href="https://twitter.com/#!/way0utwest">twitter</a>). This month’s topic is “<a href="https://voiceofthedba.wordpress.com/2012/02/07/t-sql-tuesday-027-the-big-data-valentines-edition/">Big Data</a>”.</p>
<h2>Purge Problems in Big Data &ndash; Not only a SELECT needs an index</h2>
<p>
Recently I was called to an issue at a 5+ TB customer. The purge job had stopped working a while back and the disk drives started to feel all bloated. 
</p>
<p>
The purge job ran every night to delete data older than n days. It would execute for over 13 hours and than quit reporting that there were not enough resources to complete the query.
</p>
<p>
The procedure would go through 5 tables and delete rows based on their relationship to "expired" records in a common parent table. After that, those parent records where supposed to get deleted. But the procedure never got to finish the third delete statement.
</p>
<p>
The problem was, that each delete would anew request the list of expired records form the parent table in a DELETE WHERE parent_id IN (SELECT id FROM parent); format. The inner select had a where clause checking a date column and an indicator column. While there was an index on the date column, SQL Server could not use it because of the age calculation performed. Also, the indicator was not part of the index. With this setup SQL Server had to perform a table scan of one of the bigger tables in that database for each of the child tables and than one more time for the parent table itself.
</p>
<p>
There are a few issues with this algorithm, including that by the time the parent table got to be purged more rows might qualify than at the time the first child was purged. That would cause foreign key violations during the delete &ndash; but the process never got that far anyway.
</p>
<p>
To resolve the issue I added the indicator to the index on the date column as an included column. I than rewrote the procedure to retrieved the ids of all to-be-purged records into a temp table, rewriting the select in a way that the index actually could be used. All the delete statements would than join to that temp table to delete the necessary rows. I also made sure that there was an index on the parent_id on each child table &ndash; a recommended best practice for all foreign key relationships anyway.
</p>
<p>
With those changes in place, the purge is now happily humming along again. What we can learn from it is the fact, that while indexes usually help SELECTs and hinder INSERTs and DELETEs, sometimes you need an index to be able to even execute your DELETE statements.
</p> <div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F666%2Fpurge-problems-tsql-tuesday-027-the-big-data-valentines-edition%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/666/purge-problems-tsql-tuesday-027-the-big-data-valentines-edition/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/666/purge-problems-tsql-tuesday-027-the-big-data-valentines-edition/"  data-text="Purge Problems [TSQL Tuesday #027 - The Big Data Valentine’s Edition]" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/666/purge-problems-tsql-tuesday-027-the-big-data-valentines-edition/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/666/purge-problems-tsql-tuesday-027-the-big-data-valentines-edition/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Purging a Table based on a Fixed Number of Rows to Keep</title>
		<link>http://sqlity.net/en/646/purging-a-table-based-on-a-fixed-number-of-rows-to-keep/</link>
		<comments>http://sqlity.net/en/646/purging-a-table-based-on-a-fixed-number-of-rows-to-keep/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 15:00:01 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[Archiving and Purging]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=646</guid>
		<description><![CDATA[Purging old data out of the database usually is driven by a date. If the business does not need records that are older than a Year, and if your records have a date column, you can purge by deleting all records from that table that have a date that is older ("&#60;") than DATEADD(year,-1,GETDATE()) Sometimes <a href="http://sqlity.net/en/646/purging-a-table-based-on-a-fixed-number-of-rows-to-keep/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
Purging old data out of the database usually is driven by a date. If the business does not need records that are older than a Year, and if your records have a date column, you can purge by deleting all records from that table that have a date that is older ("&lt;") than DATEADD(year,-1,GETDATE())
</p>
<p>
Sometimes however the purging is driven by a fixed number of rows that need to be kept. In this post I am going to show how to do this type of purging most efficiently.
<p>
<p>
For this article I am assuming that the table that needs to be purged has a clustered index on an IDENTITY column. The final solution I am going to present does not rely on that fact. However if the order of rows for the purging process is not given by the clustered index, another method might be more efficient.
</p>
<p>
To start let us create a table and insert 10000 rows into it:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
IF OBJECT_ID('dbo.ToBePurged') IS NOT NULL DROP TABLE dbo.ToBePurged;
CREATE TABLE dbo.ToBePurged(Id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, PlaceHolderForOtherColumns CHAR(400));
INSERT INTO dbo.ToBePurged(PlaceHolderForOtherColumns) SELECT TOP(10000) 'Fill' FROM sys.system_internals_partition_columns a,sys.system_internals_partition_columns b;
</pre>
</div>
<p>
One of the ways to go about this purge is to find the maximum IDENTITY value in the table and subtract the number of rows to keep from it. That will give you the largest IDENTITY value that needs to be deleted:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
DECLARE @NoRowsToKeep INT = 4864;
DELETE dbo.ToBePurged WHERE Id &lt;= (SELECT MAX(Id) - @NoRowsToKeep FROM dbo.ToBePurged);
</pre>
</div>
<p>
This looks neat, however there is a problem: If there is a gap in the IDENTITY values in the table you will end up deleting to many rows:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
IF OBJECT_ID('dbo.ToBePurged') IS NOT NULL DROP TABLE dbo.ToBePurged;
CREATE TABLE dbo.ToBePurged(Id INT IDENTITY(13,5) PRIMARY KEY CLUSTERED, PlaceHolderForOtherColumns CHAR(400));
INSERT INTO dbo.ToBePurged(PlaceHolderForOtherColumns) SELECT TOP(10000) 'Fill' FROM sys.system_internals_partition_columns a,sys.system_internals_partition_columns b;
GO
DECLARE @NoRowsToKeep INT = 4864;
DELETE dbo.ToBePurged WHERE Id &lt;= (SELECT MAX(Id) - @NoRowsToKeep FROM dbo.ToBePurged);
SELECT COUNT(1) Cnt, @NoRowsToKeep NoRowsToLeave FROM dbo.ToBePurged;
</pre>
</div>
<p>
In this example I created the table with an IDENTITY step size greater than one. This might seem arbitrary, however keep in mind that the increment of the IDENTITY value for a table never gets rolled back. So if you ever had a failing insert you also have gaps.
</p>
<p>
The result of the last query in the above example shows that there are only 973 rows left in the table instead of the expected 4864. So we need to get a little more sophisticated:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
DECLARE @NoRowsToKeep INT = 4864;
SET STATISTICS IO ON;
DELETE dbo.ToBePurged WHERE Id NOT IN (SELECT TOP(@NoRowsToKeep) Id FROM dbo.ToBePurged ORDER BY Id DESC);
SET STATISTICS IO OFF;
SELECT COUNT(1) Cnt, @NoRowsToKeep NoRowsToLeave FROM dbo.ToBePurged;
</pre>
</div>
<p>
This, and all following examples assume that the table was recreated as in the previous example. That ensures that the numbers we are going to look at are comparable.
</p>
<p>
This solution reads a total of 21412 pages while using two Clustered Index Scan RelOps and a Sort:
</p>
<div>
<pre>
Table 'ToBePurged'. Scan count 2, logical reads 11060, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 10352, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
</pre>
</div>
<div><div id="attachment_657" class="wp-caption alignnone" style="width: 705px"><a href="http://sqlity.net/en/wp-content/uploads/2012/02/purge_by_row_count_execution_plan_1.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/purge_by_row_count_execution_plan_1-1024x140.png" alt="purge by row count execution plan 1 1024x140 Purging a Table based on a Fixed Number of Rows to Keep" title="purge_by_row_count_execution_plan_1" width="695" height="95" class="size-large wp-image-657" /></a><p class="wp-caption-text">Execution Plan 1 - click to enlarge</p></div></div>
<p>
We can replace the second Scan RelOp with a Seek RelOp:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
DECLARE @NoRowsToKeep INT = 4864;
SET STATISTICS IO ON;
DELETE dbo.ToBePurged WHERE Id &lt; (SELECT MIN(Id) FROM (SELECT TOP(@NoRowsToKeep) Id FROM dbo.ToBePurged ORDER BY Id DESC)X);
SET STATISTICS IO OFF;
SELECT COUNT(1) Cnt, @NoRowsToKeep NoRowsToLeave FROM dbo.ToBePurged;
</pre>
</div>
<p>
This solution reads a total of 211156 pages while using a Clustered Index Scan and a Clustered Index Seek RelOp without a Sort:
</p>
<div>
<pre>
Table 'ToBePurged'. Scan count 2, logical reads 10804, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 10352, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
</pre>
</div>
<div><div id="attachment_656" class="wp-caption alignnone" style="width: 705px"><a href="http://sqlity.net/en/wp-content/uploads/2012/02/purge_by_row_count_execution_plan_2.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/purge_by_row_count_execution_plan_2-1024x143.png" alt="purge by row count execution plan 2 1024x143 Purging a Table based on a Fixed Number of Rows to Keep" title="purge_by_row_count_execution_plan_2" width="695" height="97" class="size-large wp-image-656" /></a><p class="wp-caption-text">Execution Plan 2 - click to enlarge</p></div></div>
<p>
If you look closely, the seek is still a scan, it just starts in the middle of the table instead of at the beginning. To find the starting point, SQL Server executes a seek operation, hence the Clustered Index Seek RelOp in the plan.
</p>
<p>
The biggest issue with both solutions is however the need of a spool. SQL Server uses an Eager Spool RelOp when it needs to delete rows from a table based on the results of a complex (enough) query. So how can we simplify this query?
</p>
<p>
When SQL Server executes the previous query, it actually does one complete table scan: The first Scan RelOp that is followed by a top reads through the first 4864 rows to determine the MIN(Id) value. The Seek RelOp then finds the first row that has an Id value smaller than that MIN value and continues to read through all remaining rows from there. The work performed is therefore one complete scan through the table.
</p>
<p>
It should reduce the complexity of this query significantly, if we could do both steps with one Clustered Index Scan RelOp. We basically want SQL Server to read through all the rows in one ordered swoop and start deleting once we are past the rows we need to keep. We can achieve that with the ROW_NUMBER() function:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
DECLARE @NoRowsToKeep INT = 4864;
SET STATISTICS IO ON;
DELETE tbp
  FROM (SELECT ROW_NUMBER() OVER(ORDER BY Id DESC) rn FROM dbo.ToBePurged) tbp
 WHERE tbp.rn &gt; @NoRowsToKeep;
SET STATISTICS IO OFF;
SELECT COUNT(1) Cnt, @NoRowsToKeep NoRowsToLeave FROM dbo.ToBePurged;
</pre>
</div>
<p>
This solution now reads only a total of 10801 pages using only one Clustered Index Scan RelOp:
</p>
<div>
<pre>
Table 'ToBePurged'. Scan count 1, logical reads 10801, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
</pre>
</div>
<div><div id="attachment_660" class="wp-caption alignnone" style="width: 705px"><a href="http://sqlity.net/en/wp-content/uploads/2012/02/purge_by_row_count_execution_plan_3.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/purge_by_row_count_execution_plan_3-1024x88.png" alt="purge by row count execution plan 3 1024x88 Purging a Table based on a Fixed Number of Rows to Keep" title="purge_by_row_count_execution_plan_3" width="695" height="59" class="size-large wp-image-660" /></a><p class="wp-caption-text">Execution Plan 3 - click to enlarge</p></div></div>
<p>
This query is making use of the fact, that SQL Server knows to delete the rows in the underlying table even so the FROM clause is referencing a sub-select. Because the sub-select does not reference any columns of the table, you do not need to worry about name collisions either. The above query works even, if the table contains a column with the name 'rn'.
</p>


</div><div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F646%2Fpurging-a-table-based-on-a-fixed-number-of-rows-to-keep%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/646/purging-a-table-based-on-a-fixed-number-of-rows-to-keep/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/646/purging-a-table-based-on-a-fixed-number-of-rows-to-keep/"  data-text="Purging a Table based on a Fixed Number of Rows to Keep" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/646/purging-a-table-based-on-a-fixed-number-of-rows-to-keep/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/646/purging-a-table-based-on-a-fixed-number-of-rows-to-keep/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

