<?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; SQL Server Internals</title>
	<atom:link href="http://sqlity.net/en/topic/general/sql-server-internals/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>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 Gap in the Identity Value Sequence</title>
		<link>http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/</link>
		<comments>http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 14:00:41 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[SQL Server Internals]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=792</guid>
		<description><![CDATA[With this blog post I am going to dive a little deeper into how SQL Server generates and handles identity values and what the implications for your code are. Your New Identity SQL Server manages identity values on a per table basis. Every time a new row gets inserted into a table, the current identity <a href="http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
With this blog post I am going to dive a little deeper into how SQL Server generates and handles identity values and what the implications for your code are.
</p>
<h3>Your New Identity</h3>
<p>
SQL Server manages identity values on a per table basis. Every time a new row gets inserted into a table, the current identity value for that table gets incremented and then used for the new row.
You can see this in action by running the following code:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
IF OBJECT_ID('dbo.TableWithIdentity') IS NOT NULL DROP TABLE dbo.TableWithIdentity;

CREATE TABLE dbo.TableWithIdentity
(
  Id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
  ExecId UNIQUEIDENTIFIER,
  RowId INT
);

SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
INSERT INTO dbo.TableWithIdentity OUTPUT INSERTED.IDENTITYCOL DEFAULT VALUES;
SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
INSERT INTO dbo.TableWithIdentity OUTPUT INSERTED.IDENTITYCOL DEFAULT VALUES;
SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
INSERT INTO dbo.TableWithIdentity OUTPUT INSERTED.IDENTITYCOL DEFAULT VALUES;
SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
</pre>
</div>
<p>
The output of this query looks like this:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/IDENT_CURRENT.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/IDENT_CURRENT.png" alt="IDENT CURRENT The Gap in the Identity Value Sequence" title="IDENT_CURRENT" width="139" height="307" class="aligncenter size-full wp-image-793" /></a>
</p>
<p>
For rows two and three you can clearly see that the value got increased first and than used, so IDENT_CURRENT returns the last used identity value for a table. When the table was just created or truncated however, IDENT_CURRENT returns the next value, not the one that was used last. That it actually is the next value you can easily test by setting the start value of the identity column to any number other than one. 
<p>Instead of the next value, I would have expected to see a NULL returned to indicate that no identity value had been used so far. However, that is not the case, so you need to be aware of this inconsistency of the IDENT_CURRENT function in you code.
</p>
<h3>Identity Transactions</h3>
<p>
Identity values do not participate in any transaction in SQL Server. When a row gets inserted, an identity value gets consumed, even if that insert fails as the following demo shows.
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
GO
INSERT INTO dbo.TableWithIdentity(RowId)VALUES('NotANumber');
GO
SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
GO
INSERT INTO dbo.TableWithIdentity(RowId)VALUES('NotANumber');
GO
SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
GO
INSERT INTO dbo.TableWithIdentity(RowId)VALUES('NotANumber');
GO
SELECT IDENT_CURRENT('dbo.TableWithIdentity') AS [IDENT_CURRENT];
</pre>
</div>
<p>
The output will look something like this.
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/IDENT_CURRENT_for_failing_insert.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/IDENT_CURRENT_for_failing_insert.png" alt="IDENT CURRENT for failing insert The Gap in the Identity Value Sequence" title="IDENT_CURRENT_for_failing_insert" width="690" height="360" class="aligncenter size-full wp-image-796" /></a>
</p>
<p>
No new row made it into the table because of the conversion errors, but the identity value got increased anyway. The reason for this is simple: To implement the identity value management transactional, a session would need to take a lock on the identity value itself for the duration of the transaction. That would force all inserts to be executed consecutively and concurrency would be practically non-existent.
</p>
<p>
There are many reasons for which an insert could fail. Examples are an illegal value as in the above example, a deadlock, a full disk drive and so on. Some of the reasons you can control by cleaning your values prior to using them, others cannot be controlled in the inserting code at all. So you really cannot assume, that you will have a gap free list of identity values in your table.
</p>
<h3>Sequence Chasms</h3>
<p>
SQL Server does not even guarantee that the identity values used by a single insert are contiguous. To prove that run the following piece of SQL code in multiple connections at the same time.
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
DECLARE @ExecId UNIQUEIDENTIFIER = NEWID();
INSERT INTO dbo.TableWithIdentity(ExecId,RowId)
SELECT @ExecId,n FROM dbo.GetNums(10000);
</pre>
</div>
<p>
<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>
The easiest way to run multiple executions of this query at the same time is to use <a href="http://www.datamanipulation.net/sqlquerystress/" title="SQL Query Stress by Adam Machanic" target="_blank">SQL Query Stress by Adam Machanic</a> as shown below.
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/03/SQLQueryStress1.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/03/SQLQueryStress1.png" alt="SQLQueryStress1 The Gap in the Identity Value Sequence" title="SQLQueryStress in action to show gaps in a single identity value run" width="635" height="432" class="aligncenter size-full wp-image-797" /></a>
</p>
<p>
After SQL Query Stress finishes execution, run the following query.
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  B.Id B_Id ,
        A.Id A_Id ,
        A.Id - B.Id Gap ,
        B.RowId B_RowId ,
        A.RowId A_RowId ,
        A.ExecId
FROM    dbo.TableWithIdentity A
        JOIN dbo.TableWithIdentity B ON A.ExecId = B.ExecId
                                        AND A.RowId = B.RowId + 1
WHERE   A.Id - B.Id &lt;&gt; 1
ORDER BY A.ExecId , B_Id;
</pre>
</div>
<p>
This query uses a self-join on the TableWithIdentity table to return a list of all rows that have a gap between their identity value and the identity value of the preceding row of the same execution. On my system it returned about 20,000 gaps (for 200,000 inserted rows in total) with sizes from 2 to 16,000.
</p>
<p>
This example has shown that even in single inserts you cannot rely on getting contiguous identity values
</p>
<h3>Replication</h3>
<p>
One final way to get gaps in your identity stream that I would like to bring up is replication. In all replication scenarios where data could flow in more that one direction, SQL Server has to manage identity ranges to prevent conflicts (see <a href="http://technet.microsoft.com/en-us/library/ms152543.aspx" target="_blank">http://technet.microsoft.com/en-us/library/ms152543.aspx</a>).
For this, SQL Server assigns a fixed interval (per article) of identity values to each participant in the replication setup. If a participant runs out of values, a new range is automatically assigned to that participant. That new range will not be adjacent to the previous one in almost all cases, causing gaps in the list of identity values. 
</p>
<p>
That means that even if you have a system that only ever inserts s single row at a time, has only a single connection, and never runs into an issue like a bug or a hard drive failure you still can end up with gaps in your identity value stream, if someone decides to add replication into the mix.
</p>
<h3>Conclusion</h3>
<p>
The way identity values are handled by SQL Server, there is no guarantee that the stream of identity values for a single table is free of gaps. Even if you think you have covered all you bases, you still might end up with gaps later on, if the business suddenly requires replication to be added into the mix. Therefor it is a best practice to never rely on contiguous identity values anywhere in your code.
</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%2F792%2Fthe-gap-in-the-identity-value-sequence%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/792/the-gap-in-the-identity-value-sequence/"></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/792/the-gap-in-the-identity-value-sequence/"  data-text="The Gap in the Identity Value Sequence" 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/792/the-gap-in-the-identity-value-sequence/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/feed/</wfw:commentRss>
		<slash:comments>2</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>Deferred Deallocations of Pages in TempDb</title>
		<link>http://sqlity.net/en/671/deferred-deallocations-of-pages-in-tempdb/</link>
		<comments>http://sqlity.net/en/671/deferred-deallocations-of-pages-in-tempdb/#comments</comments>
		<pubDate>Sun, 19 Feb 2012 15:00:53 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[SQL Server Internals]]></category>
		<category><![CDATA[TempDb]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=671</guid>
		<description><![CDATA[The other day I ran into a question on msdn:Tempdb Deallocation (dm_db_session_space_usage). A person with the pseudonym DontPageMeBro noticed an odd behavior in his SQL Server installation: The sum of the reported usage of tempdb across all sessions was often bigger than tempdb itself. Something is clearly off here, so I figured it was worth <a href="http://sqlity.net/en/671/deferred-deallocations-of-pages-in-tempdb/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
The other day I ran into a question on msdn:<a href="http://social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/af168419-5ad9-44eb-b377-fb5560c76a1b" target="_blank">Tempdb Deallocation (dm_db_session_space_usage)</a>. A person with the pseudonym DontPageMeBro noticed an odd behavior in his SQL Server installation: The sum of the reported usage of tempdb across all sessions was often bigger than tempdb itself. Something is clearly off here, so I figured it was worth digging a little deeper. 
</p>
<h3>TempDb Usage</h3>
<p>
First let us look at how to get information about tempdb usage. SQL Server provides two DMVs that return information about the space used in tempdb:
<pre>sys.dm_db_session_space_usage</pre> and <pre>sys.dm_db_task_space_usage</pre></p>
<p>
sys.dm_db_task_space_usage reports the amount of pages taken and released by a task currently running. If a request uses parallelism you might see more than one row for that request returned by this DMV.
After each task finishes, it's numbers get rolled up into the sys.dm_db_session_space_usage. So here you can see how much space in tempdb a request used in total, but this information is only available after the request is completed.
</p>
<p>
Both DMVs report the number of pages in four columns: 
<pre>user_objects_alloc_page_count, 
user_objects_dealloc_page_count, 
internal_objects_alloc_page_count, 
internal_objects_dealloc_page_count</pre>
The two "user" columns report on spaced used by user created objects like #temptables. The two "internal" columns report on objects SQL Server decided to create to support the execution of a query. Both pair are made up of a "alloc" and a "dealloc" page count column. The former is the total count of all pages that where allocated in the scope of the DMV whereas the latter contains the total count of all deallocated pages.
</p>
<p>
So, to get the current user object space allocation in tempdb for a given session, you need to subtract the "user_objects_dealloc_page_count" from the "user_objects_alloc_page_count" in both DMVs and then SUM all those values together. The following query shows how to do that for user as well as for internal space used:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT  session_id ,
        SUM(user_objects_alloc_page_count - user_objects_dealloc_page_count) CurrentUserPages,
        SUM(internal_objects_alloc_page_count - internal_objects_dealloc_page_count) CurrentInternalPages
FROM    ( SELECT  session_id ,
                  user_objects_alloc_page_count ,
                  user_objects_dealloc_page_count ,
                  internal_objects_alloc_page_count ,
                  internal_objects_dealloc_page_count
          FROM    sys.dm_db_session_space_usage
          UNION ALL
          SELECT  session_id ,
                  user_objects_alloc_page_count ,
                  user_objects_dealloc_page_count ,
                  internal_objects_alloc_page_count ,
                  internal_objects_dealloc_page_count
          FROM    sys.dm_db_task_space_usage
        ) X
GROUP BY X.session_id
ORDER BY X.session_id ASC ;
</pre>
</div>
<p>
DontPageMeBro is dealing with the problem that some users create large #temptables and then leave the session open without dropping those tables. If you have a lot of users like that your tempdb might grow to a significant size. Because it is always advisable to have tempdb on very fast storage, this problem can mean a significant cost to the business, so it makes sense to follow up and see how big the problem really is. The sys.dm_db_session_space_usage can give us that information. Every time there is a session that has more allocated than deallocated pages, that session is holding on to a temporary object. If the last request for that session has finished a while ago, that means, that space is not actually in use and those objects should have been dropped.
</p>
<h3>Counting Inaccuracies</h3>
<p>
So far the theory. However, as DontPageMeBro noticed, if a #temptable is big it seems that SQL Server sometimes forgets to count the page deallocation. So, even though the #temptable is gone, the pages are still being counted as in use by the session that created the table.
</p>
<p>
To understand what is going on here, we need to look at how SQL Server handles page deallocations after dropping an object. 
</p>
<p>
Each Table consists of at least one allocation_unit. An allocation_unit contains for example all the data pages for a given table or index. There might also be additional allocation_units holding special pages for e.g. row overflow data. Every index in turn has it's own set of allocation_units.
</p>
<p>
When dropping an object, all allocation_units belonging to that object are deallocated and all their pages are marked as free. This can take quite some time for big objects and usually this cleanup work is done synchronously, which means that the session issuing the drop request has to wait. However if the allocation unit contains more than 1024 pages, this cleanup work is deferred. The allocation_unit is marked as "DROPPED" and the link to the table is removed at the time the drop statement executes. The actual work of freeing up all those pages is then done by a cleanup process later on. This process is the same in all databases, not only tempdb.
</p>
<p>
Lets look at an example to demonstrate this:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
CREATE TABLE #temp
  (
    id INT IDENTITY ,
    name VARCHAR(100) 
  );
GO
SELECT  allocation_unit_id
INTO    #aus
FROM    tempdb.sys.system_internals_allocation_units u
        JOIN tempdb.sys.system_internals_partitions p ON u.container_id = p.partition_id
WHERE   p.object_id = OBJECT_ID('tempdb..#temp');
GO
INSERT  INTO #temp
        SELECT TOP ( 328168 )
                'FillText'
        FROM    sys.system_internals_partition_columns a ,
                sys.system_internals_partition_columns;
GO
SELECT  'A' A , *
FROM    sys.dm_db_session_space_usage
WHERE   session_id = @@SPID;

SELECT  'A' A , u.* , p.rows
FROM    tempdb.sys.system_internals_allocation_units u
        JOIN tempdb.sys.system_internals_partitions p ON u.container_id = p.partition_id
        JOIN #aus t ON u.allocation_unit_id = t.allocation_unit_id;
GO
DROP TABLE #temp;
GO
SELECT  'B' B , *
FROM    sys.dm_db_session_space_usage
WHERE   session_id = @@SPID;

SELECT  'B' B , u.*
FROM    tempdb.sys.system_internals_allocation_units u
        JOIN #aus t ON u.allocation_unit_id = t.allocation_unit_id;
IF ( @@ROWCOUNT &gt; 0 ) 
  BEGIN
    WAITFOR DELAY '00:00:06' ;
    SELECT  'C' C , *
    FROM    sys.dm_db_session_space_usage
    WHERE   session_id = @@SPID;
    
    SELECT  'C' C , *
    FROM    tempdb.sys.system_internals_allocation_units u
            JOIN #aus t ON u.allocation_unit_id = t.allocation_unit_id;
  END ;
GO

DROP TABLE #aus;
</pre>
</div>
<p>
This script creates the table #temp, fills it with a few thousand rows and then drops it again. If you run this script you will get the following output back:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/02/direct_AU_drop.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/direct_AU_drop.png" alt="direct AU drop Deferred Deallocations of Pages in TempDb " title="direct_AU_drop" width="1088" height="255" class="alignleft size-full wp-image-676" /></a>
</p>
<p>
The first result-set shows that the current session has 1019 pages currently reserved in tempdb. The second result-set tells us that the table #temp contains 328168 rows that are stored in a single allocation unit of type "IN_ROW_DATA" with 1018 pages.
</p>
<p>
The third and forth result-set were captured after the table was dropped. Here we can see that 1017 pages were deallocated in tempdb for the current connection and that the allocation_unit is now gone. (That not all pages of #temp show as being dropped in the count is due to another optimization that is not part of today's discussion.)
</p>
<p>
If we change the number of rows inserted (line 14 in above script) from 328168 to 328169 we get this output instead:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/02/deferred_AU_drop.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/deferred_AU_drop.png" alt="deferred AU drop Deferred Deallocations of Pages in TempDb " title="deferred_AU_drop" width="1089" height="303" class="alignleft size-full wp-image-677" /></a>
</p>
<p>
This time the allocation_unit has 1026 pages, so we would expect the deferred drop to take place. Result-set 4 now shows, directly after the drop table took place, that the allocation_unit is still there, but it's type changed to "DROPPED". The link to the table it once belonged to is also removed, as is visible in the container_id column.
</p>
<p>
If the above script sees that the allocation_unit still exists after the drop (see line 37) it waits for a few seconds and then looks again. In result-set 6 you can now see that the allocation_unit got removed. However the current session still shows 1027 allocated and no deallocated pages (result-set 5).
</p>
<h3>Cleaning Up</h3>
<p>
To see the cleanup process in action you can use the following script:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
CREATE TABLE #temp
  (
    id INT IDENTITY ,
    name VARCHAR(100) 
  );
GO
SELECT  allocation_unit_id
INTO    #aus
FROM    tempdb.sys.system_internals_allocation_units u
        JOIN tempdb.sys.system_internals_partitions p ON u.container_id = p.partition_id
WHERE   p.object_id = OBJECT_ID('tempdb..#temp');
GO
INSERT  INTO #temp
        SELECT TOP ( 328169 )
                'FillText'
        FROM    sys.system_internals_partition_columns a ,
                sys.system_internals_partition_columns;
GO
SELECT  'A' A , *
FROM    sys.dm_db_session_space_usage
WHERE   session_id = @@SPID;

SELECT  'A' A , u.* , p.rows
FROM    tempdb.sys.system_internals_allocation_units u
        JOIN tempdb.sys.system_internals_partitions p ON u.container_id = p.partition_id
        JOIN #aus t ON u.allocation_unit_id = t.allocation_unit_id;
GO
DROP TABLE #temp;

SELECT  IDENTITY(INT,1,1) Id,SYSDATETIME()now, u.allocation_unit_id , data_pages , type_desc
INTO    #siau
FROM    tempdb.sys.system_internals_allocation_units u
        JOIN #aus t ON u.allocation_unit_id = t.allocation_unit_id ;

SELECT IDENTITY(INT,1,1) Id,SYSDATETIME()now, *
INTO #ssu
 FROM  sys.dm_db_session_space_usage 
WHERE user_objects_dealloc_page_count&gt;0 OR session_id = @@SPID
ORDER BY session_id;

SELECT IDENTITY(INT,1,1) Id,SYSDATETIME()now, tsu.*,r.status,r.command
INTO #tsu
 FROM  sys.dm_db_task_space_usage tsu
 JOIN sys.dm_exec_requests r
 ON tsu.session_id = r.session_id
WHERE user_objects_dealloc_page_count&gt;0
ORDER BY session_id;

DECLARE @AuId BIGINT = (SELECT TOP(1) allocation_unit_id FROM #aus);
DECLARE @Stop DATETIME2 = DATEADD(SECOND,10,SYSDATETIME());
WHILE (SYSDATETIME()&lt;@Stop)
BEGIN
  INSERT   INTO    #siau
  SELECT  SYSDATETIME()now, u.allocation_unit_id , data_pages , type_desc
  FROM    tempdb.sys.system_internals_allocation_units u
  WHERE u.allocation_unit_id = @AuId;

  INSERT INTO #ssu
  SELECT SYSDATETIME()now, *
   FROM  sys.dm_db_session_space_usage 
  WHERE user_objects_dealloc_page_count&gt;0 OR session_id = @@SPID
  ORDER BY session_id;

  INSERT INTO #tsu
  SELECT SYSDATETIME()now, tsu.*,r.status,r.command
   FROM  sys.dm_db_task_space_usage tsu
   JOIN sys.dm_exec_requests r
   ON tsu.session_id = r.session_id
   AND tsu.request_id = r.request_id
  WHERE user_objects_dealloc_page_count&gt;0
  ORDER BY session_id;
END

SELECT MIN(now) MinNow,MAX(now) MaxNow,type_desc,data_pages,allocation_unit_id
FROM #siau
GROUP BY type_desc,data_pages,allocation_unit_id
ORDER BY MIN(Id) ASC;

SELECT MIN(now) MinNow,MAX(now) MaxNow,session_id,database_id,user_objects_alloc_page_count,user_objects_dealloc_page_count,internal_objects_alloc_page_count,internal_objects_dealloc_page_count 
FROM #ssu 
GROUP BY session_id,database_id,user_objects_alloc_page_count,user_objects_dealloc_page_count,internal_objects_alloc_page_count,internal_objects_dealloc_page_count
ORDER BY session_id ASC, MIN(Id) ASC;

SELECT MIN(now) MinNow,MAX(now) MaxNow,status,command,session_id,request_id,exec_context_id,database_id,user_objects_alloc_page_count,user_objects_dealloc_page_count,internal_objects_alloc_page_count,internal_objects_dealloc_page_count
FROM #tsu 
GROUP BY status,command,session_id,request_id,exec_context_id,database_id,user_objects_alloc_page_count,user_objects_dealloc_page_count,internal_objects_alloc_page_count,internal_objects_dealloc_page_count
ORDER BY session_id ASC, MIN(Id) ASC;

GO
DROP TABLE #ssu;
DROP TABLE #tsu;
DROP TABLE #aus;
DROP TABLE #siau;
</pre>
</div>
<p>
This script again creates the same table #temp that was used by the previous script, fills it and drops it. After dropping the table it records for ten seconds information from the allocation_unit DMV and the two space_usage DMVs. After those ten seconds it produces this output:
</p>
<p>
<a href="http://sqlity.net/en/wp-content/uploads/2012/02/deferred_AU_drop_verbose.png"><img src="http://sqlity.net/en/wp-content/uploads/2012/02/deferred_AU_drop_verbose.png" alt="deferred AU drop verbose Deferred Deallocations of Pages in TempDb " title="deferred_AU_drop_verbose" width="1075" height="585" class="alignleft size-full wp-image-682" /></a>
</p>
<p>
The first two result-sets show us the same information about the table that we have seen before. The other three result-sets contain grouped information of the three recorded DMVs. Each is grouped by all columns but the time of capture. That means, each row shows when those values where visible first and last, so you can see the progression of events.
</p>
<p>
The third result-set tells us that right after dropping the table the allocation_unit was marked as dropped. It at this point also shows a size of 0 pages. Just a little under a second later, at 17:18:06.1417576, the allocation_unit was seen last. At 17:18:06.1387573, just barely a millisecond after dropping the table, session 8 suddenly appears and starts to deallocate pages &ndash; pages it clearly did not allocate &ndash; until it, at 17:18:06.1417576, has deallocated all 1025 pages that belonged to our allocation_unit. That is exactly the same time when the allocation_unit itself was seen last. That this process started right after dropping the table is a coincidence and you might see several seconds pass before it starts, when you try this out yourself.
</p>
<p>
During the whole time of the recording from the table drop to ten seconds later, the information returned by sys.dm_db_session_space_usage DMV did not change at all. So, while the cleanup process can be seen to deallocate pages, that information never gets rolled up into the session space DMV. The session that originally created the table also never gets updated.
</p>
<h3>Versions</h3>
<p>
I have tested this in the following versions of SQL Server:
<pre>
Microsoft SQL Server 2005 - 9.00.5057.00 (X64)
Microsoft SQL Server 2008 (SP3) - 10.0.5500.0 (X64)
Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64)
Microsoft SQL Server 2012 RC0 - 11.0.1750.32 (X64)
</pre>
All SQL Server versions listed above show the same behavior.
</p>
<h3>Conclusion</h3>
<p>
I consider this behavior a bug in SQL Server. As the last example showed, the allocation_unit gets cleaned up by a background process. At that point the link to the original table and with it the originating session is gone, so the background process cannot update the session space usage information. However, right at the time of the drop, when the allocation_unit is marked as DROPPED, it also shows a size of 0 pages. At this point the task space usage information for the request executing the drop should have been updated to also reflect the drop. The pages could at the same time appear in the allocated column of one of the "TASK MANAGER" requests that execute the background cleanup tasks to make sure that the total of all allocated and deallocated pages in those two DMVs always matches the current state of tempdb.
</p>
<p>
I created a Connect item with Microsoft for this behavior here:<a href="https://connect.microsoft.com/SQLServer/feedback/details/725621/sys-dm-db-session-space-usage-inaccurate-after-deferred-drop-of-allocation-unit" title="https://connect.microsoft.com/SQLServer/feedback/details/725621/sys-dm-db-session-space-usage-inaccurate-after-deferred-drop-of-allocation-unit" target="_blank"></a>. If you agree that this should be addressed, please go there and vote for it.
</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%2F671%2Fdeferred-deallocations-of-pages-in-tempdb%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/671/deferred-deallocations-of-pages-in-tempdb/"></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/671/deferred-deallocations-of-pages-in-tempdb/"  data-text="Deferred Deallocations of Pages in TempDb" 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/671/deferred-deallocations-of-pages-in-tempdb/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/671/deferred-deallocations-of-pages-in-tempdb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Performance Impact of Forwarded Records on Table Scans</title>
		<link>http://sqlity.net/en/609/the-performance-impact-of-forwarded-records-on-table-scans/</link>
		<comments>http://sqlity.net/en/609/the-performance-impact-of-forwarded-records-on-table-scans/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 16:00:18 +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=609</guid>
		<description><![CDATA[Forwarded records are a mechanism that SQL Server employs to reduce the amount of maintenance work for indexes on a table without a clustered index. During an update of a record in a table that does not have a clustered index, an increase in size might prevent the record to fit on its current page. <a href="http://sqlity.net/en/609/the-performance-impact-of-forwarded-records-on-table-scans/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
Forwarded records are a mechanism that SQL Server employs to reduce the amount of maintenance work for indexes on a table without a clustered index. During an update of a record in a table that does not have a clustered index, an increase in size might prevent the record to fit on its current page. If that happens, a forwarding pointer is created in the current page and the record is moved to a new location.
</p>
<p>
It is well known that such forwarded records will cause each RID-Lookup operation that encounters one to have to read a second page. If you are doing a filtered index scan followed by an RID-Lookup this can potentially double the amount of work necessary to retrieve all rows.
</p>
<p>
What is less well known is the fact, that such forwarded records can significantly impact the performance of a simple table scan as well. In this article I will show you why this happens.
</p>
<h3>Terminology</h3>
<p>
To explain the way SQL Server handles forwarded records during a table scan, I am first going to rehash some storage basics.
</p>
<p>
SQL Server knows two ways to organize the data in a table on disk. One is the Clustered Index and the other one the Heap. In a Clustered Index data is organized in a B+Tree structure allowing for fast access based on the Clustered Index Key. In a Heap on the other hand the data is not sorted or linked in any way. Any new row is inserted into the table in any free space big enough to hold the row.
</p>
<p>
In both cases the smallest unit of storage and access is a Page. Every piece of data SQL Server needs to store on disk is organized in blocks called pages. Each page is exactly 8192 Bytes in size. The only exception to this rule are the log files. Log data is stored in a structure called virtual log file and those are not part of today's discussion.
</p>
<p>
Indexes created on a Heap use a physical address to point from the index record to the underlying data record. This address consists of the file number, the number of the page that contains the record within that file and the slot number inside that page.
</p>
<h3>Forwarded Records</h3>
<p>
When a record with variable length data type columns is updated, its size might increase. If the page it is stored in is filled already, the updated record might need to be moved to a new page. If that happens, all pointers in any index on that table addressing the moved row now point to the wrong (old) place. There are two ways to handle this situation: Update all indexes with the new location or put a special record in the old place that "forwards" to the new location.
</p>
<p>
Going through all existing indexes can be extensively resource intensive. For that reason SQL Server is using the second option to put a forwarding record in the old place.
</p>
<p>
Such a forwarding record links to the new physical address of the actual data. The new record also contains a pointer back to the forwarding record. This back-pointer allows the forwarding record to get updated in case the data record has to move again or in case it gets deleted which causes the forwarding record to be deleted as well. Updating the forwarding records in cases of repeated data record moves prevents long forwarding chains. Instead there is always only at max on hop.
</p>
<p>
In the case of an RID-Lookup SQL Server has to follow those forwarding records to get to the actual data record. This causes an additional (logical) page read for each forwarding record encountered.
</p>
<p>
During a table scan on the other hand each page will be read anyway so SQL Server could just ignore all forwarding records. That however could cause reading inconsistencies. Rows that are updated after the scan started and before it finishes could be missed entirely by the scan, if the record gets moved to a page that was scanned already. For that reason SQL Server follows each forwarding record immediately. This not only causes an additional read right there, is also turns the sequential read of all pages in allocation order into a succession of random reads, hurting performance potentially even more.
</p>
<h3>Demonstration</h3>
<p>
To demonstrate this behavior let us set up two tables dbo.ForwardSmall and dbo.NoForwardSmall as well as a Procedure dbo.ChangeRow to help with the creation of forwarded records:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
IF OBJECT_ID('dbo.ForwardSmall') IS NOT NULL DROP TABLE dbo.ForwardSmall;
CREATE TABLE dbo.ForwardSmall(Id INT ,F VARCHAR(8000))
GO
IF OBJECT_ID('dbo.NoForwardSmall') IS NOT NULL DROP TABLE dbo.NoForwardSmall;
CREATE TABLE dbo.NoForwardSmall(Id INT ,F VARCHAR(8000))
GO

IF OBJECT_ID('dbo.ChangeRow') IS NOT NULL DROP PROCEDURE dbo.ChangeRow;
GO
CREATE PROCEDURE dbo.ChangeRow
@Id INT,
@Size INT
AS
BEGIN
  SET NOCOUNT ON;
  MERGE dbo.ForwardSmall fs
  USING (SELECT @Id,REPLICATE('X',@Size)) x(Id,F)
  ON fs.Id = x.Id
  WHEN MATCHED THEN
    UPDATE SET fs.F = x.F
  WHEN NOT MATCHED THEN
    INSERT (Id,F)VALUES(x.Id,x.F);
END
GO
</pre>
</div>
<p>
The procedure will take an Id parameter as well as a size parameter. It uses to merge command to either insert or update the record with the given Id value. The F column will be valued with a string of length @Size.
</p>
<p>
The following script will create 16 rows in the table dbo.ForwardSmall and then update those records to create forwarded records.
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
EXEC dbo.ChangeRow 11,900;
EXEC dbo.ChangeRow 12,900;
EXEC dbo.ChangeRow 13,900;
EXEC dbo.ChangeRow 14,900;
EXEC dbo.ChangeRow 15,900;
EXEC dbo.ChangeRow 16,900;
EXEC dbo.ChangeRow 17,900;
EXEC dbo.ChangeRow 18,900;

EXEC dbo.ChangeRow 21,900;
EXEC dbo.ChangeRow 22,900;
EXEC dbo.ChangeRow 23,900;
EXEC dbo.ChangeRow 24,900;
EXEC dbo.ChangeRow 25,900;
EXEC dbo.ChangeRow 26,900;
EXEC dbo.ChangeRow 27,900;
EXEC dbo.ChangeRow 28,900;
--------------------------
EXEC dbo.ChangeRow 27,0;
EXEC dbo.ChangeRow 28,0;
EXEC dbo.ChangeRow 18,1800;
EXEC dbo.ChangeRow 28,900;
EXEC dbo.ChangeRow 18,900;

EXEC dbo.ChangeRow 26,0;
EXEC dbo.ChangeRow 17,1800;
EXEC dbo.ChangeRow 27,900;
EXEC dbo.ChangeRow 17,900;

EXEC dbo.ChangeRow 25,0;
EXEC dbo.ChangeRow 16,1800;
EXEC dbo.ChangeRow 26,900;
EXEC dbo.ChangeRow 16,900;

EXEC dbo.ChangeRow 24,0;
EXEC dbo.ChangeRow 15,1800;
EXEC dbo.ChangeRow 25,900;
EXEC dbo.ChangeRow 15,900;


EXEC dbo.ChangeRow 23,0;
EXEC dbo.ChangeRow 14,1800;
EXEC dbo.ChangeRow 24,900;
EXEC dbo.ChangeRow 14,900;

EXEC dbo.ChangeRow 22,0;
EXEC dbo.ChangeRow 13,1800;
EXEC dbo.ChangeRow 23,900;
EXEC dbo.ChangeRow 13,900;

EXEC dbo.ChangeRow 21,0;
EXEC dbo.ChangeRow 12,1800;
EXEC dbo.ChangeRow 22,1499;
EXEC dbo.ChangeRow 12,780;

EXEC dbo.ChangeRow 11,910;

EXEC dbo.ChangeRow 22,900;
EXEC dbo.ChangeRow 21,910;
</pre>
</div>
<p>
Each record starts out with ~950 bytes, so the 16 records will fit into two pages. From there the records are updated in a way so that each of them ends up on the other page with a forwarding record in its old place.
</p>
<p>
Now lets put the exact same data into the dbo.NoForwardSmall table:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
INSERT INTO dbo.NoForwardSmall
SELECT * FROM dbo.ForwardSmall;
</pre>
</div>
<p>
This again requires two pages, but this time no forwarded records are created.
</p>
<p>
To confirm, we can use the following query using the sys.dm_db_index_physical_stats DMF:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT OBJECT_SCHEMA_NAME(object_id)+'.'+OBJECT_NAME(object_id) Tbl,index_type_desc,alloc_unit_type_desc,page_count,record_count,forwarded_record_count
FROM sys.dm_db_index_physical_stats(DB_ID(),NULL,NULL,NULL,'detailed') ps
WHERE object_id IN (OBJECT_ID('dbo.ForwardSmall'),OBJECT_ID('dbo.NoForwardSmall'));
</pre>
</div>
<p>
This query returns the number of pages, the total number of records and the number of forwarded records for each table:
</p>
<div>
<style type="text/css">
table.tableizer-table {border: 1px solid #CCC; font-family: Arial, Helvetica, sans-serif; font-size: 12px;} .tableizer-table td {padding: 4px; margin: 3px; border: 1px solid #ccc;}
.tableizer-table th {background-color: #104E8B; color: #FFF; font-weight: bold;}
</style>
<table class="tableizer-table">
<tr class="tableizer-firstrow"><th>Tbl</th><th>index_type_desc</th><th>alloc_unit_type_desc</th><th>page_count</th><th>record_count</th><th>forwarded_record_count</th></tr> <tr><td>dbo.ForwardSmall</td><td>HEAP</td><td>IN_ROW_DATA</td><td>2</td><td>32</td><td>16</td></tr> <tr><td>dbo.NoForwardSmall</td><td>HEAP</td><td>IN_ROW_DATA</td><td>2</td><td>16</td><td>0</td></tr></table>
</div>
<p>
Now let us look at what happens during a table scan:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SET STATISTICS IO ON;
SELECT * FROM dbo.NoForwardSmall;
GO
SELECT * FROM dbo.ForwardSmall;
SET STATISTICS IO OFF;
</pre>
</div>
<p>
This produces the following output:
</p>
<div>
<pre>
(16 row(s) affected)
Table 'NoForwardSmall'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(16 row(s) affected)
Table 'ForwardSmall'. Scan count 1, logical reads 18, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
</pre>
</div>
<p>
Scanning the dbo.NoForwardSmall table caused 2 logical reads - one for each page of the table. Scanning the dbo.ForwardSmall table however caused 18 logical reads. That is almost ten times more. Each of the 16 records caused an additional page read.
</p>
<h3>Conclusion</h3>
<p>
This article showed that SQL Server follows each forwarding record it encounters right away. This not only happens in the case of an RID-Lookup but also in the case of a table scan. These additional reads can present a significant performance impact. If you have a decently sized table with variable length columns and with regular update activity, add this behavior to the list of reasons why the table really should have a clustered index. 
</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%2F609%2Fthe-performance-impact-of-forwarded-records-on-table-scans%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/609/the-performance-impact-of-forwarded-records-on-table-scans/"></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/609/the-performance-impact-of-forwarded-records-on-table-scans/"  data-text="The Performance Impact of Forwarded Records on Table Scans" 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/609/the-performance-impact-of-forwarded-records-on-table-scans/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/609/the-performance-impact-of-forwarded-records-on-table-scans/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

