<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>Michael Zilberstein SQL Server Blog</title><link>http://www.sqljunkies.com/WebLog/mz1313/default.aspx</link><description /><dc:language>en-US</dc:language><generator>CommunityServer 1.0 (Build: 1.0.1.50214)</generator><item><title>So long and thanks for all the fish</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2008/03/01/106310.aspx</link><pubDate>Sat, 01 Mar 2008 13:16:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:106310</guid><dc:creator>mz1313</dc:creator><slash:comments>1967</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/106310.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=106310</wfw:commentRss><description>This is my last post on SQLJunkies. I'm moving to sqlblog.com - welcome to my new &lt;a href="http://sqlblog.com/blogs/michael_zilberstein/default.aspx"&gt;blog&lt;/a&gt;. It's empty meanwhile but not for long. Since nice part of my RSS feeds subscription belongs to sqlblog.com bloggers (&lt;a href="http://sqlblog.com/blogs/kalen_delaney/default.aspx"&gt;Kalen Delaney&lt;/a&gt;, &lt;a href="http://sqlblog.com/blogs/adam_machanic/default.aspx"&gt;Adam Machanic&lt;/a&gt;, &lt;a href="http://sqlblog.com/blogs/denis_gobo/default.aspx"&gt;Denis Gobo&lt;/a&gt;, &lt;a href="http://sqlblog.com/blogs/linchi_shea/default.aspx"&gt;Linchi Shea&lt;/a&gt; etc), I was more than happy to receive an offer to move there. So... see you in &lt;a href="http://sqlblog.com/blogs/michael_zilberstein/default.aspx"&gt;my new blog&lt;/a&gt;.&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=106310" width="1" height="1"&gt;</description></item><item><title>Cursor</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2008/02/02/Cursors_are_powerful_for_good_and_for_bad.aspx</link><pubDate>Sat, 02 Feb 2008 17:59:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:105098</guid><dc:creator>mz1313</dc:creator><slash:comments>5</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/105098.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=105098</wfw:commentRss><description>Cursors are powerful - for good and for bad. In hands of a programmer that doesn't understand it cursors can be painful. Real-life example of cursor that never returns....(&lt;a href="http://www.sqljunkies.com/WebLog/mz1313/archive/2008/02/02/Cursors_are_powerful_for_good_and_for_bad.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=105098" width="1" height="1"&gt;</description></item><item><title>RIP: Ken Henderson</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2008/01/31/RIP_Ken_Henderson.aspx</link><pubDate>Thu, 31 Jan 2008 11:34:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:104578</guid><dc:creator>mz1313</dc:creator><slash:comments>0</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/104578.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=104578</wfw:commentRss><description>RIP: Ken Henderson
Ken Henderson passed away last Sunday...(&lt;a href="http://www.sqljunkies.com/WebLog/mz1313/archive/2008/01/31/RIP_Ken_Henderson.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=104578" width="1" height="1"&gt;</description></item><item><title>Storage engine and locking - nondeterministic behavior</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2007/07/25/Storage_engine_and_locking.aspx</link><pubDate>Wed, 25 Jul 2007 09:43:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:50261</guid><dc:creator>mz1313</dc:creator><slash:comments>0</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/50261.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=50261</wfw:commentRss><description>This post (or maybe series of 2 posts) is inspired by short discussion in one of the Israely SQL Server user group meetings; Ami Levin - SQL Server MVP - mentioned that when you query first row of the page, SQL Server goes not only to the page itself but also to the previous page because the same value can be in the end of the previous page also. Ami said that he himself had found it together with Itizk Ben-Gan after hot discussion that almost ended in a fight :-). &lt;br&gt;&lt;br&gt;Background for the beginning. The problem occurs when SQL Server uses index seek. It starts from non-leaf levels of an index. Non-leaf level row contains PageID and indexed column values of the first row on the leaf-level page (I'm talking about the lowest non-leaf level row). Here is example of the data on such page (data refers to the demo below; c1 and c2 are indexed columns):&lt;br&gt;
&lt;font face="Courier New" size="2"&gt;&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;PageID&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Col1&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Col2&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;171&lt;/td&gt;&lt;td&gt;476&lt;/td&gt;&lt;td&gt;476&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;173&lt;/td&gt;&lt;td&gt;952&lt;/td&gt;&lt;td&gt;952&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;175&lt;/td&gt;&lt;td&gt;1428&lt;/td&gt;&lt;td&gt;1428&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/font&gt;&lt;br&gt;

It means that Col1 value in the first row of page 171 is 476, in the first row of page 173 is 952 etc. But nobody can garantee that 952 can't be the value of Col1 also in the last row of page 171. Or in some number of last rows - nobody garanteed that index on Col1 is unique. Although all this explanation looked pretty logical, I still found it hard to believe that SQL Server behaviour can be such undeterministic - same query on the same data sometimes locks 1 row and sometimes more. So I decided to check. I created table with 2 integer columns c1 and c2, both are primary key though in fact c1 is also unique.&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff" size="2"&gt;IF&lt;/font&gt; &lt;font color="#808080" size="2"&gt;EXISTS(&lt;/font&gt; &lt;font color="#0000ff" size="2"&gt;SELECT&lt;/font&gt; 1 &lt;font color="#0000ff" size="2"&gt;FROM&lt;/font&gt; &lt;font color="#008000" size="2"&gt;sys.databases&lt;/font&gt; &lt;font color="#0000ff" size="2"&gt;WHERE&lt;/font&gt; [name] = &lt;font color="#ff0000" size="2"&gt;'LocksDemo'&lt;/font&gt; &lt;font color="#808080" size="2"&gt;)&lt;/font&gt;&lt;br&gt;
	&lt;font color="#0000ff" size="2"&gt;DROP DATABASE&lt;/font&gt; LocksDemo&lt;br&gt;
GO&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;CREATE DATABASE&lt;/font&gt; LocksDemo&lt;br&gt;
GO&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;USE&lt;/font&gt; [LocksDemo]&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff" size="2"&gt;CREATE TABLE&lt;/font&gt; Demo( c1 &lt;font color="#0000ff" size="2"&gt;INT&lt;/font&gt; &lt;font color="#808080" size="2"&gt;NOT NULL&lt;/font&gt;, c2 &lt;font color="#0000ff" size="2"&gt;INT&lt;/font&gt; &lt;font color="#808080" size="2"&gt;NOT NULL&lt;/font&gt; )&lt;br&gt;
GO&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;ALTER TABLE&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;ADD CONSTRAINT&lt;/font&gt; PK_Demo &lt;font color="#0000ff" size="2"&gt;PRIMARY KEY CLUSTERED&lt;/font&gt; (c1, c2)&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;set nocount on&lt;br&gt;
begin&lt;br&gt;
declare&lt;/font&gt; @i &lt;font color="#0000ff" size="2"&gt;int&lt;/font&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;set&lt;/font&gt; @i = 0&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;while&lt;/font&gt; @i &amp;lt; 2000 &lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt; begin&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; insert into&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;values&lt;/font&gt; (@i, @i)&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;set &lt;/font&gt;@i = @i + 1&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;end&lt;/font&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;end&lt;/font&gt;&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

My DBID is 7, objectID of Demo table is 2137058649. First of all let's see what pages does Demo table occupy.&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;DBCC&lt;/font&gt; TRACEON(3604); GO;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;DBCC&lt;/font&gt; IND(7, 2137058649, -1);&lt;br&gt;
The table contains one IAM page, 1 non-leaf level index page and 5 leaf-level clustered index pages (data pages actually).&lt;br&gt;&lt;br&gt;

&lt;font size="-2"&gt;&lt;i&gt;BTW, question for storage engine geeks: data page in my example contains 476 records. Record lenght is 15 byte (for the explanation of what else besides data each row contains see &lt;a href="http://www.amazon.com/Inside-Microsoft-SQL-Server-2005/dp/0735621055"&gt;this&lt;/a&gt; great book by Kalen Delaney). FLOOR(8060 / 15) = 537. So I counted 537 should-be-rows but you can check DBCC PAGE yourself - page contains only 476 rows. So where is the space for another 61 rows? Hint: fillfactor is not the answer.&lt;/i&gt;&lt;/font&gt;&lt;br&gt;&lt;br&gt;

In my case first row of page 171 (second leaf-level page) starts from row (476; 476). Le't start from second row in order to see IO and locks:&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;set statistics io on&lt;br&gt;
begin tran&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;with&lt;/font&gt;(rowlock, xlock) &lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 477&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;exec&lt;/font&gt; &lt;font color="#800000"&gt;sp_lock&lt;/font&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;commit tran&lt;/font&gt;&lt;br&gt;&lt;br&gt;

Since shared lock on row is released immidiately after row had been read, I lock it exclusively using &lt;i&gt;xlock&lt;/i&gt; hint in order to be able to see the lock using &lt;font color="#800000"&gt;sp_lock&lt;/font&gt;. The result is as expected: 2 reads (one non-leaf level page and one leaf-level), 1 exclusive key lock (plus intent exclusive on page and on table). Now let's query first row of the page:&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff" size="2"&gt;set statistics io on&lt;br&gt;
begin tran&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;with&lt;/font&gt;(rowlock, xlock) &lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 476&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;exec&lt;/font&gt; &lt;font color="#800000"&gt;sp_lock&lt;/font&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;commit tran&lt;/font&gt;&lt;br&gt;&lt;br&gt;

Now we have 3 reads, still 1 key lock but 2 intent exclusive locks on pages. So it really goes to previous page. OK, let's try to lock previous page and see what happens.&lt;br&gt;&lt;br&gt;

&lt;font face="Courier New"&gt;&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 1 (SPID 53)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 2 (SPID 55)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;begin tran&lt;/font&gt;&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;with&lt;/font&gt;(paglock, xlock)&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 470&lt;/td&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 476&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/font&gt;&lt;br&gt;

It is really waiting for the first transaction to release the lock on page that doesn't contain any rows that answer to the query criteria! Here is what &lt;font color="#800000"&gt;sp_lock&lt;/font&gt; shows:&lt;br&gt;

&lt;font face="Courier New"&gt;&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;SPID&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Type&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Resource&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Mode&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Status&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;53&lt;/td&gt;&lt;td&gt;PAG&lt;/td&gt;&lt;td&gt;1:169&lt;/td&gt;&lt;td&gt;X&lt;/td&gt;&lt;td&gt;GRANT&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;55&lt;/td&gt;&lt;td&gt;PAG&lt;/td&gt;&lt;td&gt;1:169&lt;/td&gt;&lt;td&gt;IS&lt;/td&gt;&lt;td&gt;WAIT&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/font&gt;&lt;br&gt;

Just wanted to remind that the relevant row is on page 171, not on 169. Now let's try to reverse scan order of session 2 and see what does it lock:&lt;br&gt;

&lt;font face="Courier New"&gt;&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 1 (SPID 53)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 2 (SPID 55)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;begin tran&lt;/font&gt;&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;with&lt;/font&gt;(paglock, xlock)&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 470&lt;/td&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 476&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;order by&lt;/font&gt; c1 &lt;font color="#0000ff" size="2"&gt;desc&lt;/font&gt;, c2 &lt;font color="#0000ff" size="2"&gt;desc&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/font&gt;&lt;br&gt;

Results of &lt;font color="#800000"&gt;sp_lock&lt;/font&gt;:&lt;br&gt;
&lt;font face="Courier New"&gt;&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;SPID&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Type&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Resource&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Mode&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Status&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;53&lt;/td&gt;&lt;td&gt;PAG&lt;/td&gt;&lt;td&gt;1:169&lt;/td&gt;&lt;td&gt;X&lt;/td&gt;&lt;td&gt;GRANT&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;55&lt;/td&gt;&lt;td&gt;PAG&lt;/td&gt;&lt;td&gt;1:169&lt;/td&gt;&lt;td&gt;IX&lt;/td&gt;&lt;td&gt;WAIT&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;55&lt;/td&gt;&lt;td&gt;PAG&lt;/td&gt;&lt;td&gt;1:171&lt;/td&gt;&lt;td&gt;IX&lt;/td&gt;&lt;td&gt;GRANT&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/font&gt;&lt;br&gt;

Session 2 has read the relevant row on page 171 and now waits for session 1 to release lock on page 169 in order to check whether it also contains relevant rows.&lt;br&gt;&lt;br&gt;

BTW, all this doesn't happen when you specify both c1 and c2 in search criteria:&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 476 &lt;font color="#808080" size="2"&gt;and&lt;/font&gt; c2 = 476&lt;br&gt;&lt;br&gt;
Why? Because SQL Server knows that c1 and c2 together are unique (they're primary key, remember?). So if it is first row on page 171, there can't be another row with the same value on any other page. On the other hand, adding unique index on c1 doesn't help initial query - it still goes to previous page - but somehow it reverses scan order of session 2 from backward to forward. Don't have a clue, why it is implemented this way.&lt;br&gt;&lt;br&gt;

To end with -  two funny consequences of all this mess. Do you think that select of 1 row that uses index seek in read committed isolation level can't cause deadlock? You're wrong!&lt;br&gt;
&lt;font face="Courier New"&gt;&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 1 (SPID 53)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 2 (SPID 55)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;begin tran&lt;/font&gt;&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;with&lt;/font&gt;(paglock, xlock)&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 470&lt;/td&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 476&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;order by&lt;/font&gt; c1 &lt;font color="#0000ff" size="2"&gt;desc&lt;/font&gt;, c2 &lt;font color="#0000ff" size="2"&gt;desc&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;with&lt;/font&gt;(rowlock, xlock)&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 476 &lt;font color="#808080" size="2"&gt;and&lt;/font&gt; c2 = 476&lt;/td&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/font&gt;&lt;br&gt;
Session 2 selected only 1 row and it was enough for deadlock. Session 2 was also the one to survive while session 1 had been chosen as deadlock victim.&lt;br&gt;&lt;br&gt;

Last trick: I add column c3 to the table and create unique index on it:&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;CREATE TABLE&lt;/font&gt; Demo( c1 &lt;font color="#0000ff" size="2"&gt;INT&lt;/font&gt; &lt;font color="#808080" size="2"&gt;NOT NULL&lt;/font&gt;, c2 &lt;font color="#0000ff" size="2"&gt;INT&lt;/font&gt; &lt;font color="#808080" size="2"&gt;NOT NULL&lt;/font&gt;, c3 &lt;font color="#0000ff" size="2"&gt;INT&lt;/font&gt; &lt;font color="#808080" size="2"&gt;NOT NULL&lt;/font&gt; )&lt;br&gt;
GO&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;ALTER TABLE&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;ADD CONSTRAINT&lt;/font&gt; PK_Demo &lt;font color="#0000ff" size="2"&gt;PRIMARY KEY CLUSTERED&lt;/font&gt; (c1, c2)&lt;br&gt;
GO&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;CREATE UNIQUE INDEX&lt;/font&gt; IX_Demo_c3 &lt;font color="#0000ff" size="2"&gt;ON&lt;/font&gt; Demo(c3)&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff" size="2"&gt;set nocount on&lt;br&gt;
begin&lt;br&gt;
declare&lt;/font&gt; @i &lt;font color="#0000ff" size="2"&gt;int&lt;/font&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;set&lt;/font&gt; @i = 0&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;while&lt;/font&gt; @i &amp;lt; 2000 &lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt; begin&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; insert into&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;values&lt;/font&gt; (@i, @i, @i)&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;set &lt;/font&gt;@i = @i + 1&lt;br&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#0000ff" size="2"&gt;end&lt;/font&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;end&lt;/font&gt;&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

Now last record in the first page contains values (384, 384, 384), first row of the second page contains (385, 385, 385). And don't forget, c3 is unique.&lt;br&gt;&lt;br&gt;

&lt;font face="Courier New"&gt;&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 1 (SPID 53)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;Session 2 (SPID 55)&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;begin tran&lt;/font&gt;&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo &lt;font color="#0000ff" size="2"&gt;with&lt;/font&gt;(paglock, xlock)&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 470&lt;/td&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;select&lt;/font&gt; c1, c2 &lt;font color="#0000ff" size="2"&gt;from&lt;/font&gt; Demo&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 476&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;order by&lt;/font&gt; c1 &lt;font color="#0000ff" size="2"&gt;desc&lt;/font&gt;, c2 &lt;font color="#0000ff" size="2"&gt;desc&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;font color="#0000ff" size="2"&gt;delete from&lt;/font&gt; Demo&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 385 &lt;font color="#808080" size="2"&gt;and&lt;/font&gt; c2 = 385&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;update&lt;/font&gt; Demo&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;set&lt;/font&gt; c1 = 385, c3 = 385&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;where&lt;/font&gt; c1 = 384 &lt;font color="#808080" size="2"&gt;and&lt;/font&gt; c2 = 384&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff" size="2"&gt;commit tran&lt;/font&gt;&lt;/td&gt;&lt;td&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/font&gt;&lt;br&gt;

Resultset of session 2:&lt;br&gt;&lt;font face="Courier New"&gt;
&lt;table cellpadding="3" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;c1&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;c2&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;&lt;u&gt;c3&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;385&lt;/td&gt;&lt;td&gt;385&lt;/td&gt;&lt;td&gt;&lt;font color="#ff0000" size="2"&gt;385&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;385&lt;/td&gt;&lt;td&gt;384&lt;/td&gt;&lt;td&gt;&lt;font color="#ff0000" size="2"&gt;385&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/font&gt;&lt;br&gt;

Are you really, really sure c3 is unique?&lt;br&gt;&lt;br&gt;
&lt;font size="2"&gt;
I hope to write at least one more post on this theme - next time I will play around with different isolation levels.&lt;br&gt;&lt;br&gt;

*** &lt;font size="-2"&gt;&lt;i&gt;Answer for the question about missing rows on page: remember, in the end of the page there is an offset array - for each row it contains an offset from the page start. Since we have pretty many rows on page, offset array also requires significant space.&lt;/i&gt;&lt;/font&gt;&lt;/font&gt;&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=50261" width="1" height="1"&gt;</description></item><item><title>Linked server and timestamp column</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2007/03/20/29410.aspx</link><pubDate>Tue, 20 Mar 2007 09:52:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:29410</guid><dc:creator>mz1313</dc:creator><slash:comments>0</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/29410.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=29410</wfw:commentRss><description>Something that looks like bug. Luckily, with workaround.&lt;br&gt;
Let's say, you have MS SQL 2K on Server1 (I have SP4 - didn't check it on other configurations). Steps to reproduce the bug:&lt;br&gt;
1) Create table with timestamp column (or add timestamp column to existing table) and populate with some data.&lt;br&gt;
&lt;br&gt;
&lt;font color="#0000ff"&gt;CREATE TABLE&lt;/font&gt; TSTest (c1 &lt;font color="#0000ff"&gt;INT&lt;/font&gt;, TS &lt;font color="#0000ff"&gt;TIMESTAMP &lt;/font&gt;&lt;font color="#c0c0c0"&gt;NOT NULL&lt;/font&gt;)&lt;br&gt;
GO&lt;br&gt;
&lt;font color="#0000ff"&gt;INSERT INTO&lt;/font&gt; TSTest (c1) &lt;br&gt;
&lt;font color="#0000ff"&gt;SELECT TOP&lt;/font&gt; 100 [id]&lt;br&gt; 
&lt;font color="#0000ff"&gt;FROM &lt;/font&gt;&lt;font color="#008000"&gt;sysobjects&lt;/font&gt;&lt;br&gt;
GO&lt;br&gt;
&lt;br&gt;
2) From another server "Server2" with SQL2K or SQL2K5 create linked server to Server1 using the following provider:&lt;br&gt;
&lt;br&gt;
&lt;font color="#0000ff"&gt;EXEC &lt;/font&gt;master.dbo.&lt;font color="#804000"&gt;sp_addlinkedserver&lt;/font&gt; @server = N&lt;font color="#ff0000"&gt;'Server1'&lt;/font&gt;, @srvproduct=N&lt;font color="#ff0000"&gt;'OLE DB Provider for ODBC'&lt;/font&gt;, @provider=N&lt;font color="#ff0000"&gt;'MSDASQL'&lt;/font&gt;, @provstr=N&lt;font color="#ff0000"&gt;'DRIVER={SQL Server};SERVER=Server1;'&lt;/font&gt;&lt;br&gt;
GO&lt;br&gt;
&lt;br&gt;
Configure it to use the appropriate user (the problem is not security, so you can give it even sa).&lt;br&gt;
&lt;br&gt;
3) Try to query the table via linked server.&lt;br&gt;
&lt;br&gt;
&lt;font color="#0000ff"&gt;SELECT TOP&lt;/font&gt; 10 &lt;font color="#c0c0c0"&gt;*&lt;/font&gt; &lt;font color="#0000ff"&gt;FROM &lt;/font&gt;Server1.DBA.dbo.TSTest&lt;br&gt;
GO&lt;br&gt;
&lt;br&gt;
Error message returns:&lt;br&gt;
&lt;font color="#ff0000"&gt;Msg 7356, Level 16, State 1, Line 1&lt;/font&gt;&lt;br&gt;
&lt;font color="#ff0000"&gt;The OLE DB provider "MSDASQL" for linked server "Server1" supplied inconsistent metadata for a column. The column "TS" (compile-time ordinal 2) of object ""DBA"."dbo"."TSTest"" was reported to have a "DBCOLUMNFLAGS_ISROWVER" of 0 at compile time and 512 at run time.&lt;/font&gt;&lt;br&gt;
&lt;br&gt;
The message above is from SQL2K5. SQL 2K returns less specific message - in order to see the detailed one trace flag 7300 should be turned on. Needless to say, no DML operation had been performed on the table during the query via linked server. So timestamp column values hadn't changed.&lt;br&gt;
&lt;br&gt;
&lt;u&gt;Workaround:&lt;/u&gt;&lt;br&gt;
&lt;br&gt;
1) Use another provider (not MSDASQL). In SQL2K5, Native Client (SQLNCLI) works fine though it has other problems: from time to time Distributed Transactions Coordinator unexpectedly aborts my transaction - out of the blue without any particular reason I can put my finger on. Not sure, I'll investigate it further because of (2):&lt;br&gt;
&lt;br&gt;
2) Use OPENQUERY. It just works.&lt;br&gt;
&lt;br&gt;
&lt;font color="#0000ff"&gt;SELECT&lt;/font&gt; &lt;font color="#c0c0c0"&gt;*&lt;/font&gt; &lt;font color="#0000ff"&gt;FROM OPENQUERY&lt;/font&gt;(Server1, &lt;font color="#ff0000"&gt;'SELECT TOP 10 * FROM DBA.dbo.TSTest'&lt;/font&gt;)&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=29410" width="1" height="1"&gt;</description></item><item><title>Saving Auto Recovery Information</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2007/02/16/28256.aspx</link><pubDate>Fri, 16 Feb 2007 16:53:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:28256</guid><dc:creator>mz1313</dc:creator><slash:comments>2</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/28256.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=28256</wfw:commentRss><description>If you have bad luck of working with Management Studio via VPN connection (maybe other slow connections as well - I experience it only via VPN), I'm sure that you're familiar with this situation: your screen is frozen, you stare on it with angry look on your face and see just a small line in a bottom left corner of your Management Studio saying: "Saving Auto Recovery Information". Last time when I worked from home with my version script (about 50K rows), the "Saving..." process had been taking about 5 minutes every time. So, here is the way to get rid of it. Go to Registry and change to 0 (zero) value of the following key:&lt;br&gt;
HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\90\Tools\Shell\General\AutoRecover\AutoRecover Enabled&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=28256" width="1" height="1"&gt;</description></item><item><title>TABLOCKX</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2007/01/09/26704.aspx</link><pubDate>Wed, 10 Jan 2007 01:00:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:26704</guid><dc:creator>mz1313</dc:creator><slash:comments>2</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/26704.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=26704</wfw:commentRss><description>BOL states:&lt;br&gt; 
&lt;i&gt;TABLOCKX&lt;br&gt;
Specifies that an exclusive lock is taken on the table. If HOLDOCK is also specified, the lock is held until the transaction completes&lt;/i&gt;&lt;br&gt;&lt;br&gt;

So it's not stated explicitly that without HOLDLOCK the lock is held until end-of-statement. But as far as my english - or logic - goes, I understood it that way. Otherwise - why to mention HOLDLOCK if TABLOCKX itself does the same? Let's check. Before opening transaction, I'll make some preparations.&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;CREATE DATABASE&lt;/font&gt; Demo&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;USE &lt;/font&gt;[Demo]&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;CREATE TABLE&lt;/font&gt; TabLockDemo( col1 &lt;font color="#0000ff"&gt;INT&lt;/font&gt;, col2 &lt;font color="#0000ff"&gt;VARCHAR&lt;/font&gt;(8000) )&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;INSERT INTO&lt;/font&gt; TabLockDemo&lt;br&gt;
&lt;font color="#0000ff"&gt;VALUES&lt;/font&gt;(1, &lt;font color="#ff0000"&gt;'a'&lt;/font&gt;)&lt;br&gt;
GO&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;SELECT&lt;/font&gt; &lt;font color="#ff00ff"&gt;OBJECT_ID&lt;/font&gt;(&lt;font color="#ff0000"&gt;'TabLockDemo'&lt;/font&gt;)&lt;br&gt;
&lt;font color="#008000"&gt;-- 2073058421&lt;/font&gt;&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;SELECT &lt;/font&gt;&lt;font color="#ff00ff"&gt;@@SPID&lt;/font&gt;&lt;br&gt;
&lt;font color="#008000"&gt;-- 52&lt;/font&gt;&lt;br&gt;&lt;br&gt;

Now let's set isolation level to read committed, open transaction and select data from a table using TABLOCKX hint:&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;SET TRANSACTION ISOLATION LEVEL READ&lt;/font&gt; COMMITTED&lt;br&gt;
&lt;font color="#0000ff"&gt;
BEGIN TRAN&lt;br&gt;&lt;br&gt;
&lt;/font&gt;
&lt;font color="#0000ff"&gt;SELECT TOP&lt;/font&gt; 1 * &lt;font color="#0000ff"&gt;FROM &lt;/font&gt;TabLockDemo &lt;font color="#0000ff"&gt;WITH&lt;/font&gt;(TABLOCKX)&lt;br&gt;&lt;br&gt;

Now, in order to be sure that the statement ended, I would even execute another statement:&lt;br&gt;&lt;br&gt;

&lt;font color="#0000ff"&gt;SELECT TOP &lt;/font&gt;1 * &lt;font color="#0000ff"&gt;FROM &lt;/font&gt;&lt;font color="#008000"&gt;sys.indexes&lt;/font&gt;&lt;br&gt;&lt;br&gt;

Now let's see, what sp_lock tells us... The table is locked! You don't believe? Open another session and try to execute &lt;font color="#0000ff"&gt;SELECT&lt;/font&gt; * &lt;font color="#0000ff"&gt;FROM &lt;/font&gt;TabLockDemo.
The reason for this behaviour is pretty obvious. Exclusive lock is usually being used for DML operations - not for SELECT. But if we open transaction, execute some INSERT statement and hold the lock only for the duration of a statement, then we can now read this data from another session - the table isn't locked. Afterwards we rollback the first session and so we've got classical dirty read! Thus exclusive lock is always being held until the end of transaction - without any need of HOLDLOCK. BOL is at least misleading.&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=26704" width="1" height="1"&gt;</description></item><item><title>Insert data via linked server - SQL2005 behaves differently</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/09/26/23677.aspx</link><pubDate>Tue, 26 Sep 2006 15:51:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:23677</guid><dc:creator>mz1313</dc:creator><slash:comments>72</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/23677.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=23677</wfw:commentRss><description>Something I ran into just recently. I have pretty big - 7Gb - table on Server1 that needs to be transfered to Server2 via linked server from Server2 to Server1.
&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff"&gt;INSERT INTO&lt;/font&gt; MyTable&lt;br&gt;
&lt;font color="#0000ff"&gt;SELECT &lt;/font&gt;&lt;font color="#808080"&gt;*&lt;/font&gt; &lt;font color="#0000ff"&gt;FROM &lt;/font&gt;Server1.MyDB.dbo.MyTable
&lt;br&gt;&lt;br&gt;
I have a simple select that gives me datafile data for an active db:&lt;br&gt;&lt;br&gt;
&lt;u&gt;For SQL Server 2000 (BTW, works in SQL2005 too):&lt;/u&gt; 
&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff"&gt;SELECT &lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#ff00ff"&gt;filegroup_name&lt;/font&gt;(groupid) &lt;font color="#0000ff"&gt;as &lt;/font&gt;Filegroup,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[name],&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[filename],&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[size]/128.0 &lt;font color="#0000ff"&gt;as &lt;/font&gt;TotalSizeInMB,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#ff00ff"&gt;FILEPROPERTY&lt;/font&gt;([name], &lt;font color="#ff0000"&gt;'SpaceUsed'&lt;/font&gt;)/128.0 &lt;font color="#0000ff"&gt;as &lt;/font&gt;SpaceUsedInMB,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;([size] - &lt;font color="#ff00ff"&gt;FILEPROPERTY&lt;/font&gt;([name], &lt;font color="#ff0000"&gt;'SpaceUsed'&lt;/font&gt;))/128.0 &lt;font color="#0000ff"&gt;as &lt;/font&gt;FreeSpaceInMB&lt;br&gt;
&lt;font color="#0000ff"&gt;FROM &lt;/font&gt;&lt;font color="#008000"&gt;sysfiles&lt;/font&gt;&lt;br&gt;&lt;br&gt;

&lt;u&gt;For SQL Server 2005:&lt;/u&gt;
&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff"&gt;SELECT &lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[name],&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[physical_name],&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[size]/128.0 &lt;font color="#0000ff"&gt;as &lt;/font&gt;TotalSizeInMB,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#ff00ff"&gt;FILEPROPERTY&lt;/font&gt;([name], &lt;font color="#ff0000"&gt;'SpaceUsed'&lt;/font&gt;)/128.0 &lt;font color="#0000ff"&gt;as &lt;/font&gt;SpaceUsedInMB,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;([size] - &lt;font color="#ff00ff"&gt;FILEPROPERTY&lt;/font&gt;([name], &lt;font color="#ff0000"&gt;'SpaceUsed'&lt;/font&gt;))/128.0 &lt;font color="#0000ff"&gt;as&lt;/font&gt; FreeSpaceInMB,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;CASE&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;WHEN &lt;/font&gt;is_percent_growth = 1 &lt;font color="#0000ff"&gt;THEN &lt;/font&gt;&lt;font color="#ff00ff"&gt;CAST&lt;/font&gt;(growth &lt;font color="#0000ff"&gt;as &lt;/font&gt;VARCHAR(8)) + &lt;font color="#ff0000"&gt;'%'&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;ELSE &lt;/font&gt;&lt;font color="#ff00ff"&gt;CAST&lt;/font&gt;(&lt;font color="#ff00ff"&gt;FLOOR&lt;/font&gt;(growth/128.0) &lt;font color="#0000ff"&gt;as &lt;/font&gt;VARCHAR(8)) + &lt;font color="#ff0000"&gt;'MB'&lt;/font&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;END as&lt;/font&gt; growth,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[is_read_only]&lt;br&gt;
&lt;font color="#0000ff"&gt;FROM &lt;/font&gt;sys.database_files&lt;br&gt;
&lt;font color="#0000ff"&gt;ORDER BY&lt;/font&gt; [Name] &lt;font color="#0000ff"&gt;ASC&lt;/font&gt;&lt;br&gt;&lt;br&gt;

When I execute my query in SQL Server 2000 database, datafile and log in the MyTable immidiately start to grow. When I execute it on SQL Server 2005 db (while Server1 is SQL2000 - I didn't test it on two SQL2005 servers but I would be surprised if that matters), datafiles in my db don't grow. What grows instead is tempdb! I guess it has something to do with version stores though snapshot isolation is turned off.&lt;br&gt;&lt;br&gt;&lt;u&gt;Update:&lt;/u&gt; After some thought seems that I begin to understand the issue. In SQL 2000 &lt;i&gt;deleted&lt;/i&gt; and &lt;i&gt;inserted&lt;/i&gt; tables (which are used in triggers) aren't actually tables but are derived from transaction log. In SQL 2005 on the other hand &lt;i&gt;deleted&lt;/i&gt; and &lt;i&gt;inserted&lt;/i&gt; are managed by tempDB via version store mechanism. So TempDB grows as a substitute to transaction log.&lt;br&gt;&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=23677" width="1" height="1"&gt;</description></item><item><title>Kalen Delaney started blogging</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/09/12/23432.aspx</link><pubDate>Tue, 12 Sep 2006 05:16:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:23432</guid><dc:creator>mz1313</dc:creator><slash:comments>113</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/23432.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=23432</wfw:commentRss><description>http://sqlblog.com/blogs/kalen_delaney/default.aspx&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=23432" width="1" height="1"&gt;</description></item><item><title>DBCC CHECKDB</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/06/14/21874.aspx</link><pubDate>Wed, 14 Jun 2006 07:07:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:21874</guid><dc:creator>mz1313</dc:creator><slash:comments>1</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/21874.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=21874</wfw:commentRss><description>It appears that DBCC CHECKDB can cause performance degradation immidiately after it finishes. KB article is &lt;a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;917828&amp;amp;sd=rss&amp;amp;spid=2855"&gt;here&lt;/a&gt;. In short, DBCC CHECKDB clears the whole procedure cache. Thus you can't reuse already compiled execution plans - they are just not there.&lt;br&gt;&lt;br&gt;
Another issue with DBCC CHECKDB that concerns only SQL Server 2005. In order to make DBCC CHECKDB run on transactionally consistent database, Yukon uses snapshot. It's hidden, so you can't tune it or even place at specific disk. The problem can occur when you have:&lt;br&gt;
1. Large DB (so that DBCC CHECKDB takes significant time to complete)&lt;br&gt;
2. Many DML operations at different tables (thus snapshot size will grow fast)&lt;br&gt;
3. Low free space on disk.&lt;br&gt;
So be careful - if your database usage patterns are similar to (1) and (2), verify that you have enough free space on disk prior to executing DBCC CHECKDB.&lt;br&gt;
BTW, In SQL Server 2000 that's not the case. In order to provide transactional consistency it uses some clever mechanism that knows to integrate with transaction log.&lt;br&gt;
&lt;a href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/09/623789.aspx"&gt;Here&lt;/a&gt; is the detailed explanation (1st part of the future serie) about how DBCC CHECKDB works written by the guy that programmed it. &lt;br&gt;BTW, &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=449554&amp;amp;SiteID=1"&gt;here&lt;/a&gt; you can ask him to add more issues to the scope of the serie.&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=21874" width="1" height="1"&gt;</description></item><item><title>Auto-indexing solution for SQL Server 2005 and other stuff</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/06/05/21728.aspx</link><pubDate>Mon, 05 Jun 2006 07:46:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:21728</guid><dc:creator>mz1313</dc:creator><slash:comments>2</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/21728.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=21728</wfw:commentRss><description>Looks like really helpful tool from SQL Query Optimization team at Microsoft. &lt;a href="http://blogs.msdn.com/queryoptteam/archive/2006/06/01/613516.aspx"&gt;Auto-indexing solution&lt;/a&gt; based on Missing Index DMVs - now works in recomendation mode but can be easily transformed to a fully automated tool. It also knows to clean up the mess - not only to create missing indexes but also to drop unnecessary ones. Though I wouldn't recommend to execute it in fully automated mode - at least not for dropping indexes. Take the tool's recommendations and check them first.&lt;br&gt;&lt;br&gt;Another promising tool: &lt;a href="http://msdn.microsoft.com/vstudio/teamsystem/products/dbpro/default.aspx"&gt;Visual Studio Team Edition for Database Professionals&lt;/a&gt; is due to be released at June 9th. Visual Studio + Team System + DB source control and, listen carefully, schema control - all in one tool. Hopefully also integrated together.&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=21728" width="1" height="1"&gt;</description></item><item><title>Server trace enabled by default in SQL Server 2005</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/05/09/20962.aspx</link><pubDate>Tue, 09 May 2006 07:04:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:20962</guid><dc:creator>mz1313</dc:creator><slash:comments>2298</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/20962.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=20962</wfw:commentRss><description>Is your SQL Server 2005 surprisingly slow? It maybe because server trace runs on your server though you never started it! It comes out that '&lt;font color="#ff0000"&gt;default trace enabled&lt;/font&gt;' setting is turned on (1) by default during SQL Server 2005 installation. In order to verify it you can execute: &lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff"&gt;select&lt;/font&gt; * &lt;font color="#0000ff"&gt;from &lt;/font&gt;&lt;font color="#008000"&gt;sys.configurations&lt;/font&gt; &lt;font color="#0000ff"&gt;where&lt;/font&gt; configuration_id = 1568&lt;br&gt;&lt;br&gt;
In order to check whether you have active traces runnig, execute:&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff"&gt;select &lt;/font&gt;* &lt;font color="#0000ff"&gt;from &lt;/font&gt;::fn_trace_getinfo(0)&lt;br&gt;&lt;br&gt;
If you have active traces (you'll see trace IDs and paths to .trc files), you can stop them in the following way: for each active trace ID execute (stop trace at first step and clear trace definition from the server at a second):&lt;br&gt;&lt;br&gt;
&lt;font color="#0000ff"&gt;exec&lt;/font&gt; sp_trace_setstatus ActiveTraceID, 0&lt;br&gt;
&lt;font color="#0000ff"&gt;exec&lt;/font&gt; sp_trace_setstatus ActiveTraceID, 2&lt;br&gt;&lt;br&gt;

On the other hand, this trace is very light and according to BOL also useful: BOL states, that "Default trace provides troubleshooting assistance to database administrators by ensuring that they have the log data necessary to diagnose problems the first time they occur." Also if you turn off the trace, you won't have the option to debug stored procedures from Management Studio 2005.&lt;br&gt;&lt;br&gt;
&lt;font size="-2"&gt;Via: Alex Lerner (SRL Tech Ltd.)&lt;/font&gt;&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=20962" width="1" height="1"&gt;</description></item><item><title>DBCC DBREINDEX</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/04/09/20235.aspx</link><pubDate>Sun, 09 Apr 2006 08:27:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:20235</guid><dc:creator>mz1313</dc:creator><slash:comments>1396</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/20235.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=20235</wfw:commentRss><description>In BOL for SQL 2K we read, that SORTED_DATA and SORTED_DATA_REORG clauses that existed in SQL Server 6.x are no longer supported in SQL 2K. Don't believe that, they are not just supported but even used by Maintenance Plan. Add Optimization step to your plan and query sysprocesses table when it runs - you'll see something like:

&lt;br&gt;&lt;br&gt;&lt;font color="#000000" face="Courier New"&gt;&lt;font color="#0000ff"&gt;dbcc&lt;/font&gt; dbreindex(&lt;font color="#ff0000"&gt;N'[dbo].[MyTable]'&lt;/font&gt;, &lt;font color="#ff0000"&gt;N''&lt;/font&gt;, 90, sorted_data_reorg)&lt;br&gt;&lt;br&gt;&lt;/font&gt;

But don't get used to it - in SQL 2K5 SORTED_DATA and SORTED_DATA_REORG clauses don't exist.&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=20235" width="1" height="1"&gt;</description></item><item><title>HowTo: delete old backups as part of maintenance plan in SQL Server 2005</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/04/03/20010.aspx</link><pubDate>Mon, 03 Apr 2006 08:13:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:20010</guid><dc:creator>mz1313</dc:creator><slash:comments>21</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/20010.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=20010</wfw:commentRss><description>In SQL 2000 there is nothing easier then that - just choose required options in the Complete Backup and/or Transaction Log Backup tabs. In SQL 2005 those who try to create Maintenance Plan using a wizard, usually ask aftewards, where did they miss the "delete old backups" option. The answer is: nowhere. There is no such option in a wizard. In order to delete old backups one should open existing plan (created with a wizard, for example) in SSIS window (open Management Studio, Management --&gt; Maintenance Plans, right click on your plan --&gt; Modify) and add "Maintenance Plan Cleanup" task.&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=20010" width="1" height="1"&gt;</description></item><item><title>SQL Server 2005 Service Pack 1 - Community Technology Preview (CTP)</title><link>http://www.sqljunkies.com/WebLog/mz1313/archive/2006/03/19/19404.aspx</link><pubDate>Sun, 19 Mar 2006 06:19:00 GMT</pubDate><guid isPermaLink="false">d2584c15-f6ef-46f7-a2d4-24fc0e143e76:19404</guid><dc:creator>mz1313</dc:creator><slash:comments>803</slash:comments><comments>http://www.sqljunkies.com/WebLog/mz1313/comments/19404.aspx</comments><wfw:commentRss>http://www.sqljunkies.com/WebLog/mz1313/commentrss.aspx?PostID=19404</wfw:commentRss><description>&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=39ebef74-1c29-49fe-8221-c94f2b52f6c6&amp;amp;DisplayLang=en"&gt;SQL Server 2005 Service Pack 1 - Community Technology Preview (CTP)&lt;/a&gt;&lt;br&gt;&lt;br&gt;The great news is that Database Mirroring will now be officially supported in production.&lt;br&gt;&lt;img src="http://www.sqljunkies.com/WebLog/aggbug.aspx?PostID=19404" width="1" height="1"&gt;</description></item></channel></rss>