<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tag 'transaction log'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=transaction+log&amp;orTags=0</link><description>Search results matching tag 'transaction log'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Geek City: What Triggered This Post?</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2012/12/31/what-triggered-this-post.aspx</link><pubDate>Tue, 01 Jan 2013 00:00:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:46911</guid><dc:creator>Kalen Delaney</dc:creator><description>&lt;p&gt;I’d really like to get another post up onto my much neglected blog before the end of 2012. This will also start one of my New Year’s resolutions, which is to write at least one blog post a month. I’m going to tell you about a change in SQL Server that wasn’t announced in any “What’s New” list that I ever saw, perhaps because it was just a chance in internal behavior, and nothing that required any change in user applications. &lt;/p&gt;  &lt;p&gt;Do you retest what you know is true for every new version? When I update my books, I do test all the scripts, but if there isn’t a script, I don’t retest every ‘fact’ that I have known for years is true. And sometimes, things change. And sometimes my reviewers notice those unreported changes, and sometimes they don’t. &lt;/p&gt;  &lt;p&gt;You might be aware of the fact that SQL Server can perform UPDATE operations in two different ways. The UPDATE can be performed as a two-step process: delete the old row and then insert a whole new row, or, the UPDATE can be performed (much more efficiently) as an update-in-place.&amp;nbsp; When the two-step UPDATE is performed, it is a LOT more work. Not only does SQL Server have to log the entire old row and the entire new row, but each nonclustered index is also modified twice, and each of those index changes also has to be logged. So it’s nice when an update-in-place is done, because only the bytes changed are logged, and only indexes on the updated columns are affected. &lt;/p&gt;  &lt;p&gt;Prior to SQL Server 7, there were actually four different ways that UPDATE could be done. The two-step UPDATE had some variations that could make it even slower in some cases! But that was a long time ago, so I’m not going to go into the details now. But I will say that back then, in order to get an update-in-place to occur, there was a big long list of prerequisites that had to be met and if you missed just one, you’d get one of the slower UPDATE operations. &lt;/p&gt;  &lt;p&gt;As of SQL Server 7, update-in-place became the default. The only time it doesn’t happen is when the row can’t stay in the same location (such as when you update a clustered index key column) or when SQL Server really needs the old and new versions of the row. &lt;/p&gt;  &lt;p&gt;In SQL 7, one of the places that SQL needed the old and new version of the updates rows was when processing triggers. Triggers need the transaction log to get the contents for the DELETED and INSERTED pseudo-tables. And because triggers needed the entire old and new versions of the updated rows, the UPDATE was performed as a two-step operation. DELETE the old row, log the entire old row, and the INSERT the new row with the new values, and log the entire new row. &lt;/p&gt;  &lt;p&gt;But as of 2005, we now have the version store, primarily used for SNAPSHOT isolation, but available for other uses as well. In SNAPSHOT isolation, the version stores stores ‘old versions’ of rows that have been updated or deleted.&amp;nbsp; I knew that the version store was also used for triggers, but it only occurred to me just recently that maybe, because the old and new versions of the row were not needed from the log, perhaps UPDATEs did not always need to be performed internally as a two-step UPDATE. &lt;/p&gt;  &lt;p&gt;So I decided to test it out.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;-- DEMO: If there is an UPDATE trigger, are updates logged as DELETE + INSERT?        &lt;br&gt;-- First build a new database.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;USE master;        &lt;br&gt;GO         &lt;br&gt;IF (SELECT db_id('TestTrigger')) IS NOT NULL         &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP DATABASE TestTrigger;         &lt;br&gt;GO         &lt;br&gt;CREATE DATABASE TestTrigger;         &lt;br&gt;GO         &lt;br&gt;ALTER DATABASE TestTrigger SET RECOVERY SIMPLE;         &lt;br&gt;GO         &lt;br&gt;SELECT db_id('TestTrigger');         &lt;br&gt;GO &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;USE TestTrigger;        &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;-- Just for a warmup, look at the function fn_dblog, which works in the current database&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;SELECT * FROM fn_dblog(null, null);        &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- Create a new table to work with        &lt;br&gt;IF (SELECT object_id('objects')) IS NOT NULL         &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP TABLE objects;         &lt;br&gt;GO         &lt;br&gt;SELECT TOP 100 * INTO objects FROM sys.objects;         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- Create a clustered index on the table        &lt;br&gt;CREATE CLUSTERED INDEX objects_clustered on objects(name);         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- First examine an update we know is NOT done in place,        &lt;br&gt;-- i.e. updating a clustered key value&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;UPDATE objects SET name = 'newrowsets' WHERE name = 'sysrowsets';        &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- Look at last 10 rows; notice a LOP_DELETE_ROWS and LOP_INSERT_ROWS        &lt;br&gt;-- The AllocUniteName column shows the object affected is the clustered index on dbo.objects         &lt;br&gt;SELECT Operation, [Transaction ID], AllocUnitName FROM fn_dblog(null, null);         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;-- Now examine an update we know is&amp;nbsp; done in place,        &lt;br&gt;-- i.e. updating an unindexed column on a table with no triggers         &lt;br&gt;UPDATE objects SET parent_object_id = 1 WHERE name = 'sysfiles1';         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- Look at last 3 rows; notice a LOP_MODIFY_ROW on the dbo.objects allocation unit        &lt;br&gt;SELECT Operation, [Transaction ID], AllocUnitName FROM fn_dblog(null, null);         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- Create an update trigger        &lt;br&gt;-- Will the update be done with the siple LOP_MODIFY_ROW or with the LOP_DELETE_ROWS and LOP_INSERT_ROWS         &lt;br&gt;CREATE TRIGGER trg_update_objects ON objects FOR UPDATE         &lt;br&gt;as         &lt;br&gt;SELECT * FROM DELETED; SELECT * FROM INSERTED;         &lt;br&gt;RETURN;         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- Now perform update again        &lt;br&gt;UPDATE objects SET parent_object_id = 10 WHERE name = 'sysfiles1';         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;-- Look at last 3 rows; notice a LOP_MODIFY_ROW        &lt;br&gt;SELECT * FROM fn_dblog(null, null);         &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Since the database is in SIMPLE recovery model, you can issue a CHECKPOINT before each UPDATE if you want to reduce the number of rows in the log to make it easier to examine. &lt;/p&gt;  &lt;p&gt;So it seems that I need to update my course and some of my writings. There might also be special cases that still require that an two-step UPDATE be performed in the presence of triggers, but it seems like a two-step UPDATE is not ALWAYS required anymore. That is very good news!&lt;/p&gt;  &lt;p&gt;I hope you all have a wonder-filled and joyous New Year!&lt;/p&gt;  &lt;p&gt;&lt;font color="#800040" size="4"&gt;~Kalen&lt;/font&gt;&lt;/p&gt;</description></item><item><title>Follow-up Answers for my Australia Classes</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2012/04/04/follow-up-answers-for-my-australia-classes.aspx</link><pubDate>Wed, 04 Apr 2012 22:56:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:42698</guid><dc:creator>Kalen Delaney</dc:creator><description>&lt;P&gt;I was out of the country for the last two weeks of March, delivering classes in Brisbane and Sydney, which were organized by &lt;A href="http://www.wardyit.com/default.aspx"&gt;WardyIT&lt;/A&gt;.&amp;nbsp; It was a great visit and there were 24 terrific students!&lt;/P&gt;
&lt;P&gt;As is sometimes (perhaps often?)&amp;nbsp; the case, there were questions posed that I couldn’t answer during class, so here are a couple of follow-up answers.&lt;/P&gt;
&lt;P&gt;1. I brought up the fact that SQLS 2012 generates a warning message when there are ‘too many’ Virtual Log Files (VLFs) in a database. (It turns out the message will be generated when a database has more than 10,000 VLFs but the error says that the database has more than 1000 VLFs! Which is of course, technically true, but the message is a little misleading.)&amp;nbsp; A student reported hearing that the Best Practices Analyzer also had a warning about the number of VLFs, but didn’t know what that limit was, and asked if I knew. I didn’t then, but I do&amp;nbsp; now. A message will be generated by BPA when there are 1000 or more VLFs. The message is actually focused on the &lt;A href="http://sqlblog.com/blogs/linchi_shea/archive/2009/02/09/performance-impact-a-large-number-of-virtual-log-files-part-i.aspx"&gt;performance problems that can arise&lt;/A&gt; when there are two many VLFs. The boot message is more concerned with the impact on database restore, rollback, backup and recovery of too many VLFs. &lt;/P&gt;
&lt;P&gt;2. When discussing locks, I briefly mention the BU lock that is acquired by request (with a hint) during bulk load operations, for the purpose of allowing multiple processes to load into the same table concurrently. Someone asked whether any SSIS components used the BU lock, and I thought it was probably true, but I since I don’t work with SSIS, I couldn’t comment any deeper. I was able to discover, thanks to SQL Server MVPs Paul White and Arthur Zubarev that it definitely is possible for both SQL Destinations and OLE DB Destinations. The destination table must be a heap, and you can specify TABLOCK as an option for the FastLoadOptions property, as shown:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/Kalen_3DAB1AA7.jpg"&gt;&lt;IMG style="BACKGROUND-IMAGE:none;BORDER-BOTTOM:0px;BORDER-LEFT:0px;PADDING-LEFT:0px;PADDING-RIGHT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;PADDING-TOP:0px;" title=Kalen border=0 alt=Kalen src="http://sqlblog.com/blogs/kalen_delaney/Kalen_thumb_34DB125B.jpg" width=244 height=181&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;3. I very briefly mention Extended Events on the very last day, and mention that in SQL Server 2008 one of the drawbacks is that there is no GUI option to set up an XEvents session, but that has changed in SQL Server 2012. I was asked if the 2012 Management Studio could connect to a SQL Server 2008 instance and set up an XEvents session on that instance. My friend and fellow MVP Ben Miller was able to verify that when connecting from the SQL 2012 GUI to a 2008 instance, the option for creating an XEvents session does not even show up.&amp;nbsp; You could try scripting a session created for a 2012 instance and running it on a 2008 instance, but there are no guarantees. &lt;/P&gt;
&lt;P&gt;So now I’ll get back to working on my new book …&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;</description></item><item><title>Page splits, extended events, index page allocation and all the fish</title><link>http://sqlblog.com/blogs/michael_zilberstein/archive/2011/04/25/35175.aspx</link><pubDate>Mon, 25 Apr 2011 19:49:45 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:35175</guid><dc:creator>mz1313</dc:creator><description>&lt;p&gt;2 years ago I wrote about &lt;a title="Monitoring page splits with Extended Events" href="http://sqlblog.com/blogs/michael_zilberstein/archive/2009/02/05/11734.aspx"&gt;monitoring page splits with Extended Events&lt;/a&gt;. Only &lt;a title="Jonathan Kehayias" href="http://sqlblog.com/blogs/jonathan_kehayias/"&gt;2&lt;/a&gt; &lt;a title="Bob Beauchemin" href="http://www.sqlskills.com/BLOGS/BOBB/"&gt;bloggers&lt;/a&gt; explored Extended Events feature at that time, so my post was more of a learning than for any practical matter. Yet one question remained open: according to straightforward calculations, after 3 splits of the first page, next split should have occurred on another page - but trace with extended events clearly showed 4 splits of initial page.&lt;/p&gt;  &lt;p&gt;Recently Pavel Nefyodov has drawn my attention to another curious fact: initially we had 1 page; after all those splits we had 10. But trace showed 10 splits, not 9. So where did additional split come from? And finally I've realized that there is another simple way to trace those splits - via transaction log. If we manually checkpoint the system before and perform insert in transaction afer - our transaction log will containg exactly the relevant data; and it'll remain this way all the time transaction stays open. We'll query transaction log using undocumented but widely known fn_dblog function.&lt;/p&gt;  &lt;p&gt;OK, Let's see some code (mostly taken from my old post which in turn used page split demo from &lt;a title="Geek City: Splitting a page into multiple pages" href="http://sqlblog.com/blogs/kalen_delaney/archive/2008/12/20/splitting-a-page-into-multiple-pages.aspx"&gt;Kalen Delaney's blog&lt;/a&gt;). Initial configuration (including trace definition):&lt;/p&gt;  &lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;USE &lt;/span&gt;&lt;span style="color:black;"&gt;tempdb&lt;/span&gt;&lt;span style="color:gray;"&gt;;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE TABLE &lt;/span&gt;&lt;span style="color:black;"&gt;split_page&amp;#160;&amp;#160; &lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;id &lt;/span&gt;&lt;span style="color:blue;"&gt;INT &lt;/span&gt;&lt;span style="color:#434343;"&gt;IDENTITY&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;PRIMARY KEY&lt;/span&gt;&lt;span style="color:gray;"&gt;,        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;id2 bigint &lt;/span&gt;&lt;span style="color:blue;"&gt;DEFAULT &lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;,        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;data1 &lt;/span&gt;&lt;span style="color:blue;"&gt;VARCHAR&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;33&lt;/span&gt;&lt;span style="color:gray;"&gt;) NULL,&amp;#160;&amp;#160; &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;data2 &lt;/span&gt;&lt;span style="color:blue;"&gt;VARCHAR&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;8000&lt;/span&gt;&lt;span style="color:gray;"&gt;) NULL);        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;INSERT INTO &lt;/span&gt;&lt;span style="color:black;"&gt;split_page &lt;/span&gt;&lt;span style="color:blue;"&gt;DEFAULT VALUES&lt;/span&gt;&lt;span style="color:gray;"&gt;;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO 385        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE &lt;/span&gt;&lt;span style="color:black;"&gt;EVENT SESSION MonitorPageSplits &lt;/span&gt;&lt;span style="color:blue;"&gt;ON &lt;/span&gt;&lt;span style="color:black;"&gt;SERVER        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;ADD &lt;/span&gt;&lt;span style="color:black;"&gt;EVENT sqlserver.page_split        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;(        &lt;br /&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:black;"&gt;ACTION &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;sqlserver.database_id&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;sqlserver.sql_text&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:blue;"&gt;WHERE &lt;/span&gt;&lt;span style="color:black;"&gt;sqlserver.database_id &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;2        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;)        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;ADD &lt;/span&gt;&lt;span style="color:black;"&gt;TARGET package0.asynchronous_file_target        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;(        &lt;br /&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:blue;"&gt;SET&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:black;"&gt;filename &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:red;"&gt;N'c:\temp\MonitorPageSplits.etx'&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:black;"&gt;metadatafile &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:red;"&gt;N'c:\temp\MonitorPageSplits.mta'        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;);        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;CHECKPOINT        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;Short glance at our table's allocation inside data file:&lt;/p&gt;  &lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;DBCC &lt;/span&gt;&lt;span style="color:black;"&gt;IND&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;tempdb&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;split_page&lt;/span&gt;&lt;span style="color:gray;"&gt;, -&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;);        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;   &lt;table cellspacing="0" cellpadding="2"&gt;       &lt;tr&gt;         &lt;td align="center"&gt;&lt;b&gt;PagePID&lt;/b&gt;&lt;/td&gt;          &lt;td align="center"&gt;&lt;b&gt;IndexID&lt;/b&gt;&lt;/td&gt;          &lt;td align="center"&gt;&lt;b&gt;iam_chain_type&lt;/b&gt;&lt;/td&gt;          &lt;td align="center"&gt;&lt;b&gt;PageType&lt;/b&gt;&lt;/td&gt;          &lt;td align="center"&gt;&lt;b&gt;IndexLevel&lt;/b&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td&gt;175&lt;/td&gt;          &lt;td&gt;1&lt;/td&gt;          &lt;td&gt;In-row data&lt;/td&gt;          &lt;td&gt;10&lt;/td&gt;          &lt;td&gt;NULL&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td&gt;148&lt;/td&gt;          &lt;td&gt;1&lt;/td&gt;          &lt;td&gt;In-row data&lt;/td&gt;          &lt;td&gt;1&lt;/td&gt;          &lt;td&gt;0&lt;/td&gt;       &lt;/tr&gt;     &lt;/table&gt; &lt;/p&gt;  &lt;p&gt;So we have 1 IAM page and 1 data page. Now the split itself and - remember, we should query transaction log before committing transaction if we don't want accidental checkpoint to ruine all our efforts.&lt;/p&gt;  &lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;ALTER &lt;/span&gt;&lt;span style="color:black;"&gt;EVENT SESSION MonitorPageSplits &lt;/span&gt;&lt;span style="color:blue;"&gt;ON &lt;/span&gt;&lt;span style="color:black;"&gt;SERVER STATE &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;start&lt;/span&gt;&lt;span style="color:gray;"&gt;;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SET IDENTITY_INSERT &lt;/span&gt;&lt;span style="color:black;"&gt;split_page&amp;#160; &lt;/span&gt;&lt;span style="color:blue;"&gt;ON&lt;/span&gt;&lt;span style="color:gray;"&gt;;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;BEGIN TRAN        &lt;br /&gt;        &lt;br /&gt;INSERT INTO &lt;/span&gt;&lt;span style="color:black;"&gt;split_page &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;id&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;id2&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;data1&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;data2&lt;/span&gt;&lt;span style="color:gray;"&gt;)        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color:black;"&gt;111&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:magenta;"&gt;REPLICATE&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'a'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;33&lt;/span&gt;&lt;span style="color:gray;"&gt;), &lt;/span&gt;&lt;span style="color:magenta;"&gt;REPLICATE&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'b'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;8000&lt;/span&gt;&lt;span style="color:gray;"&gt;);        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SET IDENTITY_INSERT &lt;/span&gt;&lt;span style="color:black;"&gt;split_page&amp;#160; &lt;/span&gt;&lt;span style="color:blue;"&gt;OFF&lt;/span&gt;&lt;span style="color:gray;"&gt;;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO        &lt;br /&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color:black;"&gt;[Current LSN]&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;Operation&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;Context&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;span style="color:black;"&gt;[Page ID]&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;[Description]          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;&lt;span style="color:darkred;"&gt;fn_dblog&lt;/span&gt;&lt;span style="color:gray;"&gt;(NULL, NULL)          &lt;br /&gt;          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;COMMIT          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO          &lt;br /&gt;          &lt;br /&gt;ALTER &lt;/span&gt;&lt;span style="color:black;"&gt;EVENT SESSION MonitorPageSplits &lt;/span&gt;&lt;span style="color:blue;"&gt;ON &lt;/span&gt;&lt;span style="color:black;"&gt;SERVER STATE &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;STOP&lt;/span&gt;&lt;span style="color:gray;"&gt;;          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;DROP &lt;/span&gt;&lt;span style="color:black;"&gt;EVENT SESSION MonitorPageSplits &lt;/span&gt;&lt;span style="color:blue;"&gt;ON &lt;/span&gt;&lt;span style="color:black;"&gt;SERVER&lt;/span&gt;&lt;span style="color:gray;"&gt;;          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO          &lt;br /&gt;          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:black;"&gt;split.value&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'(/event/data[@name=''file_id'']/value)[1]'&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:red;"&gt;'int'&lt;/span&gt;&lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:black;"&gt;[file_id]&lt;/span&gt;&lt;span style="color:gray;"&gt;,          &lt;br /&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:black;"&gt;split.value&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'(/event/data[@name=''page_id'']/value)[1]'&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:red;"&gt;'int'&lt;/span&gt;&lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:black;"&gt;[page_id]&lt;/span&gt;&lt;span style="color:gray;"&gt;,          &lt;br /&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:black;"&gt;split.value&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'(/event[@name=''page_split'']/@timestamp)[1]'&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:red;"&gt;'datetime'&lt;/span&gt;&lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:black;"&gt;[event_time]&lt;/span&gt;&lt;span style="color:gray;"&gt;,          &lt;br /&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:black;"&gt;split.value&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'(/event/action[@name=''sql_text'']/value)[1]'&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:red;"&gt;'varchar(max)'&lt;/span&gt;&lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:black;"&gt;[sql_text]          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM          &lt;br /&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color:magenta;"&gt;CAST&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;event_data &lt;/span&gt;&lt;span style="color:blue;"&gt;AS XML&lt;/span&gt;&lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:black;"&gt;split          &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;&lt;span style="color:black;"&gt;sys.&lt;/span&gt;&lt;span style="color:darkred;"&gt;fn_xe_file_target_read_file&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'c:\temp\MonitorPageSplits*.etx'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:red;"&gt;'c:\temp\MonitorPageSplits*.mta'&lt;/span&gt;&lt;span style="color:gray;"&gt;, NULL, NULL)          &lt;br /&gt;&amp;#160;&amp;#160; ) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:black;"&gt;t          &lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;ORDER BY &lt;/span&gt;&lt;span style="color:black;"&gt;[event_time]          &lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;    &lt;p&gt;&lt;/span&gt;First let's take a look at our table now:&lt;/p&gt;    &lt;p&gt;     &lt;table cellspacing="0" cellpadding="2"&gt;         &lt;tr&gt;           &lt;td align="center"&gt;&lt;b&gt;PagePID&lt;/b&gt;&lt;/td&gt;            &lt;td align="center"&gt;&lt;b&gt;IndexID&lt;/b&gt;&lt;/td&gt;            &lt;td align="center"&gt;&lt;b&gt;iam_chain_type&lt;/b&gt;&lt;/td&gt;            &lt;td align="center"&gt;&lt;b&gt;PageType&lt;/b&gt;&lt;/td&gt;            &lt;td align="center"&gt;&lt;b&gt;IndexLevel&lt;/b&gt;&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;175&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;10&lt;/td&gt;            &lt;td&gt;NULL&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;148&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;184&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;2&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;185&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;187&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;188&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;189&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;190&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;191&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;392&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;393&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td&gt;394&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;In-row data&lt;/td&gt;            &lt;td&gt;1&lt;/td&gt;            &lt;td&gt;0&lt;/td&gt;         &lt;/tr&gt;       &lt;/table&gt;   &lt;/p&gt;    &lt;p&gt;Transaction log contains more rows than we are interested in, so I cleaned irrelevant ones out from the table below and correlated transaction log with extended events trace. I also transformed hexadecimal page numbers from transaction log to decimal ones - like we see in extended events trace.&lt;/p&gt;    &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/michael_zilberstein/WindowsLiveWriter/Pagesplitsextendedeventsindexpageallocat_12E53/image_2.png"&gt;&lt;img style="border-right-width:0px;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" border="0" alt="image" src="http://sqlblog.com/blogs/michael_zilberstein/WindowsLiveWriter/Pagesplitsextendedeventsindexpageallocat_12E53/image_thumb.png" width="770" height="355" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;So we can see that indeed there have been 3 splits of the first page. From transaction log we see that first action was actually allocating of page 184 which is - look at the allocation table above - index page. According to transaction log this page is allocated - not splitted from any other page. Still extended events trace shows as if it has been splitted from the first data page of our table. Don't know whether this behavior can be considered as bug - probably not. Anyway - both unanswered question from my old post are resolved: first page indeed has been splitted 3 times and we had only 9 data page splits while 10th split belongs to index page allocation.&lt;/p&gt;&lt;p&gt;Have a nice week!&lt;/p&gt;</description></item><item><title>Geek City: What gets logged for SELECT INTO operations?</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2011/03/15/what-gets-logged-for-select-into.aspx</link><pubDate>Tue, 15 Mar 2011 19:41:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:34163</guid><dc:creator>Kalen Delaney</dc:creator><description>&lt;p&gt;Last week, I wrote about &lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2011/03/08/what-gets-logged-for-index-rebuilds.aspx"&gt;logging for index rebuild operations.&lt;/a&gt;&amp;nbsp; I wanted to publish the result of that testing as soon as I could, because that dealt with a specific question I was trying to answer. However, I actually started out my testing by looking at the logging that was done for a different operation, and ended up generating some new questions for myself. &lt;/p&gt;
&lt;p&gt;Before I started testing the index rebuilds, I thought I would just get warmed up by observing the logging for SELECT INTO. I thought I knew what got logged, but I was wrong. My understanding was that as a minimally logged operation, in FULL recovery, SELECT INTO would log each 8K page as it was written, not each row like a normal INSERT would. In BULK_LOGGED, SELECT INTO would create a log record for each page, but it would not log the entire 8K page. And of course, it would also not log every row.&amp;nbsp; However, my first test turned up some surprising results.&lt;/p&gt;
&lt;p&gt;Here's what I did: First, I made sure the &lt;em&gt;AdventureWorks&lt;/em&gt; database was in FULL recovery, and dropped the &lt;em&gt;Details&lt;/em&gt; table if it existed. Then I created&amp;nbsp; a table called &lt;em&gt;SELECTINTOLoggingData&lt;/em&gt; to hold the results of calling &lt;em&gt;fn_dblog&lt;/em&gt;.&amp;nbsp; As in last week's script, the following information was captured:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Max log record size &lt;/li&gt;
&lt;li&gt;Sum of log record sizes &lt;/li&gt;
&lt;li&gt;Number of log records &lt;/li&gt;
&lt;li&gt;Number of log records larger than 8K &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Finally, I backed up the &lt;em&gt;AdventureWorks&lt;/em&gt; database to give me a foundation for log backups. So here's the first part of the script:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;ALTER DATABASE AdventureWorks SET RECOVERY FULL &lt;br&gt;GO &lt;br&gt;USE AdventureWorks; &lt;br&gt;GO &lt;br&gt;IF EXISTS (SELECT 1 FROM sys.tables&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &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; WHERE name = 'Details') &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP TABLE Details; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;IF EXISTS (SELECT 1 FROM sys.tables WHERE name = 'SELECTINTOLoggingData') &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP TABLE SELECTINTOLoggingData; &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;CREATE TABLE SELECTINTOLoggingData &lt;br&gt;(DBRecModel CHAR(12), MaxLogRowSize INT, NumLogRows INT, NumLargeRows INT); &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;BACKUP DATABASE AdventureWorks TO DISK = 'c:\backups\AW.bak' WITH INIT; &lt;br&gt;GO &lt;br&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The actual testing was be done first in FULL recovery, then in BULK_LOGGED. I backed up up the transaction log, then created the &lt;em&gt;Details&lt;/em&gt; table by executing a SELECT INTO from the &lt;em&gt;Sales.SalesOrderDetail&lt;/em&gt; table.&amp;nbsp; The &lt;em&gt;Details&lt;/em&gt; table has&amp;nbsp; 1495 pages and 121,317 rows. Finally, I inserted the relevant values from &lt;em&gt;fn_dblog&lt;/em&gt;&amp;nbsp; into the &lt;em&gt;SELECTINTOLoggingData &lt;/em&gt;table.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;----&amp;nbsp; &lt;font face="Consolas"&gt;FULL Recovery&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;font face="Consolas"&gt;BACKUP LOG AdventureWorks TO DISK = 'c:\backups\AW_log.bak' WITH INIT; &lt;br&gt;SELECT COUNT(*) FROM fn_dblog(null, null); &lt;br&gt;GO &lt;br&gt;SELECT * INTO Details &lt;br&gt;FROM Sales.SalesOrderDetail; &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;font face="Consolas"&gt;INSERT INTO SELECTINTOLoggingData &lt;br&gt;SELECT 'FULL', &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MAX([Log Record Length]), &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COUNT(*), &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SELECT COUNT(*) FROM fn_dblog(null, null) WHERE [Log Record Length]&amp;nbsp; &amp;gt;8000) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM fn_dblog(null, null); &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;DROP TABLE Details; &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;font face="Consolas"&gt;-- BULK_LOGGED Recovery&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;font face="Consolas"&gt;ALTER DATABASE AdventureWorks SET RECOVERY BULK_LOGGED; &lt;br&gt;BACKUP LOG AdventureWorks TO DISK = 'c:\backups\AW_log.bak' WITH INIT; &lt;br&gt;SELECT COUNT(*)&amp;nbsp; FROM fn_dblog(null, null); &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;SELECT * INTO Details &lt;br&gt;FROM Sales.SalesOrderDetail; &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;font face="Consolas"&gt;INSERT INTO SELECTINTOLoggingData &lt;br&gt;SELECT 'BULK_LOGGED', &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MAX([Log Record Length]), &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COUNT(*), &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SELECT COUNT(*) FROM fn_dblog(null, null) WHERE [Log Record Length]&amp;nbsp; &amp;gt;8000) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM fn_dblog(null, null); &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Finally, I looked at the data I collected:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;SELECT * FROM SELECTINTOLoggingData; &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Here are my results:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/kalen_delaney/image_6D32B977.png"&gt;&lt;img style="border-width:0px;padding-top:0px;padding-right:0px;padding-left:0px;display:inline;background-image:none;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/kalen_delaney/image_thumb_2A073B4A.png" width="532" height="72"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Although the number of large (8K) log rows was as expected, I was quite surprised to see the total number of log records! (And yes, I know the column names use the term "Log Rows", but I'm calling them "Log Records".&amp;nbsp; I guess I just wanted a shorter column name.)&lt;/p&gt;
&lt;p&gt;I then ran the same test on a different version of the &lt;em&gt;Sales.SalesOrderDetail&lt;/em&gt; table that I use in some of my class examples. Here is the script to create the &lt;em&gt;Sales.SalesOrderDetail2&lt;/em&gt; table&lt;em&gt;:&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;CREATE TABLE Sales.SalesOrderDetail2 ( &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [SalesOrderID] [int] NOT NULL, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [SalesOrderDetailID] [int] NOT NULL, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [CarrierTrackingNumber] [nvarchar](25) NULL, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [OrderQty] [smallint] NOT NULL, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ProductID] [int] NOT NULL, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [SpecialOfferID] [int] NOT NULL, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [UnitPrice] [money] NOT NULL, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [UnitPriceDiscount] [money] NOT NULL , &lt;br&gt;CONSTRAINT [PK_SalesOrderDetail2_SalesOrderID_SalesOrderDetailID] PRIMARY KEY CLUSTERED &lt;br&gt;( &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [SalesOrderID] ASC, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [SalesOrderDetailID] ASC &lt;br&gt;)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY] &lt;br&gt;) ON [PRIMARY]; &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;INSERT INTO Sales.SalesOrderDetail2 SELECT [SalesOrderID] &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[SalesOrderDetailID] &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[CarrierTrackingNumber] &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[OrderQty] &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[ProductID] &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[SpecialOfferID] &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[UnitPrice] &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[UnitPriceDiscount] &lt;br&gt;&amp;nbsp; FROM AdventureWorks.Sales.SalesOrderDetail; &lt;br&gt;GO&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;After setting the &lt;em&gt;AdventureWorks&lt;/em&gt; database back to FULL recovery, deleting the &lt;em&gt;Details&lt;/em&gt; table and truncating the &lt;em&gt;SELECTINTOLoggingData&lt;/em&gt; table,&amp;nbsp; I run the same test as above (starting at the "Full Recovery" comment, substituting &lt;em&gt;Sales.SalesOrderDetail2&lt;/em&gt; for &lt;em&gt;Sales.SalesOrderDetail&lt;/em&gt;. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font face="Consolas"&gt;ALTER DATABASE AdventureWorks SET RECOVERY FULL; &lt;br&gt;GO &lt;br&gt;DROP TABLE Details; &lt;br&gt;GO &lt;br&gt;TRUNCATE TABLE SELECTINTOLoggingData&lt;/font&gt;&lt;em&gt;&lt;font face="Consolas"&gt;; &lt;br&gt;GO&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Here are my new results:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/kalen_delaney/image_0913C8A3.png"&gt;&lt;img style="border-width:0px;padding-top:0px;padding-right:0px;padding-left:0px;display:inline;background-image:none;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/kalen_delaney/image_thumb_28566F76.png" width="547" height="79"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So these are much more like the results I expected from a SELECT INTO operation! &lt;/p&gt;
&lt;p&gt;Why did the first example, selecting from &lt;em&gt;Sales.SalesOrderDetail&lt;/em&gt;, do so much more logging?&lt;/p&gt;
&lt;p&gt;It turns out that if you have a &lt;strong&gt;IDENTITY&lt;/strong&gt; column in the source table, SELECT INTO must then log every row as the IDENTITY value is generated. &lt;/p&gt;
&lt;p&gt;Does this mean you should rethink the beneift of using IDENTITY columns? Only if you're doing a lot of SELECT INTO operations to copy a table with IDENTITY columns. Normal INSERT statements, which is how IDENTITY values are usually generated, are going to have the same amount of logging whether or not the table has an IDENTITY column.&amp;nbsp; (Let me know if you think otherwise.)&lt;/p&gt;
&lt;p&gt;So now you know. &lt;/p&gt;
&lt;p&gt;&lt;font color="#ff00ff" size="4"&gt;~Kalen&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;p.s. I would like to thank Sunil Agarwal for his brilliant insights and encouragement. Thanks for everything, Sunil!&lt;/p&gt;</description></item><item><title>Geek City: What gets logged for index rebuild operations?</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2011/03/08/what-gets-logged-for-index-rebuilds.aspx</link><pubDate>Tue, 08 Mar 2011 18:54:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:33967</guid><dc:creator>Kalen Delaney</dc:creator><description>&lt;P&gt;This blog post was inspired by a question from a future student. Someone who was already booked for my &lt;A href="http://sqlserverinternals.com/classes.html"&gt;SQL Server Internals class&lt;/A&gt; in June asked for some information on a current problem he was having with transaction log writes causing excessive wait times during index rebuild operations when run in ONLINE mode. He wanted to know if switching to BULK_LOGGED recovery could help. &lt;/P&gt;
&lt;P&gt;I knew the difference between ALTER INDEX in FULL vs BULK_LOGGED recovery when doing normal OFFLINE rebuilds, but I wasn't sure about ONLINE. So I dug out some old scripts, massaged them a bit, and ran some tests.&lt;/P&gt;
&lt;P&gt;A minimally logged operation is one that does not always log every single row. In FULL mode, SQL Server will log the entire page as each page is filled, so that we end up with individual&amp;nbsp; log records of over 8K. In BULK_LOGGED mode, SQL Server just logs the fact that a new page was generated (and some information about the page) and doesn't log the full 8K. So the log space used is quite a bit less. &lt;/P&gt;
&lt;P&gt;I will use Microsoft's &lt;EM&gt;AdventureWorks&lt;/EM&gt; database that you can download from &lt;A href="http://msftdbprodsamples.codeplex.com/releases/view/4004"&gt;codeplex&lt;/A&gt;. I used the SQL Server 2005 version.&lt;/P&gt;
&lt;P&gt;After making sure the database is set to FULL recovery, I make a copy of the &lt;EM&gt;Sales.SalesOrderDetail&lt;/EM&gt; table (which I call &lt;EM&gt;Details&lt;/EM&gt;) and build a clustered index on it.&amp;nbsp; The table has about 1580 pages and 121,317 rows.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT face=Consolas&gt;ALTER DATABASE AdventureWorks SET RECOVERY FULL &lt;BR&gt;GO &lt;BR&gt;USE AdventureWorks; &lt;BR&gt;GO &lt;BR&gt;IF EXISTS (SELECT 1 FROM sys.tables&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &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; WHERE name = 'Details') &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP TABLE Details; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp; &lt;BR&gt;SELECT * INTO Details &lt;BR&gt;FROM Sales.SalesOrderDetail; &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face=Consolas&gt;CREATE CLUSTERED INDEX CL_details_indx ON Details(SalesOrderID); &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I then build a table to store log information that I will gather after the different index rebuild operations. After that I back up the database to make sure I have a base for making log backups.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;IF EXISTS (SELECT 1 FROM sys.tables WHERE name = 'AlterIndexLoggingData') &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP TABLE AlterIndexLoggingData; &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;CREATE TABLE AlterIndexLoggingData &lt;BR&gt;(DBRecModel CHAR(12), IndexBuildMode CHAR(3), MaxLogRowSize INT, SumLogSize BIGINT, NumLogRows INT, NumLargeRows INT); &lt;BR&gt;GO &lt;BR&gt;BACKUP DATABASE AdventureWorks TO DISK = 'c:\backups\AW.bak' WITH INIT; &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now starts the testing. There are four sections, each of which basically does the same thing, with the four permutations of FULL vs BULK_LOGGED recovery, and ONLINE vs OFFLINE index builds.&amp;nbsp; Each section backs up the transaction log to truncate it, and then reports the number of rows in the log, just to verify we really have (logically) cleared it out. It then performs a rebuild of the index on the &lt;EM&gt;Details&lt;/EM&gt; table. Finally, it captures the following information from the log using &lt;EM&gt;fn_dblog&lt;/EM&gt;:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Max log record size &lt;/LI&gt;
&lt;LI&gt;Sum of log record sizes &lt;/LI&gt;
&lt;LI&gt;Number of log records &lt;/LI&gt;
&lt;LI&gt;Number of log records larger than 8K &lt;/LI&gt;&lt;/UL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;----&amp;nbsp; FULL Recovery, ONLINE = OFF&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;BACKUP LOG AdventureWorks TO DISK = 'c:\backups\AW_log.bak' WITH INIT; &lt;BR&gt;SELECT COUNT(*) FROM fn_dblog(null, null); &lt;BR&gt;GO &lt;BR&gt;ALTER INDEX&amp;nbsp; CL_details_indx&amp;nbsp; ON Details REBUILD &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;INSERT INTO AlterIndexLoggingData &lt;BR&gt;SELECT 'FULL', 'OFF', &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MAX([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COUNT(*), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SELECT COUNT(*) FROM fn_dblog(null, null) WHERE [Log Record Length]&amp;nbsp; &amp;gt; 8000) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM fn_dblog(null, null); &lt;BR&gt;GO &lt;BR&gt;&amp;nbsp; &lt;BR&gt;&amp;nbsp; &lt;BR&gt;--- FULL Recovery, ONLINE = ON&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT face=Consolas&gt;BACKUP LOG AdventureWorks TO DISK = 'c:\backups\AW_log.bak' WITH INIT; &lt;BR&gt;SELECT COUNT(*)&amp;nbsp; FROM fn_dblog(null, null); &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;ALTER INDEX&amp;nbsp; CL_details_indx&amp;nbsp; ON Details REBUILD &lt;BR&gt;WITH (ONLINE = ON) &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;INSERT INTO AlterIndexLoggingData &lt;BR&gt;SELECT 'FULL', 'ON', &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MAX([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COUNT(*), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SELECT COUNT(*) FROM fn_dblog(null, null) WHERE [Log Record Length]&amp;nbsp; &amp;gt; 8000) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM fn_dblog(null, null); &lt;BR&gt;GO &lt;BR&gt;--SELECT * FROM AlterIndexLoggingData; &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;--- BULK_LOGGED Recovery; ONLINE = OFF&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT face=Consolas&gt;ALTER DATABASE AdventureWorks SET RECOVERY BULK_LOGGED; &lt;BR&gt;BACKUP LOG AdventureWorks TO DISK = 'c:\backups\AW_log.bak' WITH INIT; &lt;BR&gt;SELECT COUNT(*)&amp;nbsp; FROM fn_dblog(null, null); &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;ALTER INDEX&amp;nbsp; CL_details_indx&amp;nbsp; ON Details REBUILD &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;INSERT INTO AlterIndexLoggingData &lt;BR&gt;SELECT 'BULK_LOGGED', 'OFF', &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MAX([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COUNT(*), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SELECT COUNT(*) FROM fn_dblog(null, null) WHERE [Log Record Length]&amp;nbsp; &amp;gt; 8000) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM fn_dblog(null, null); &lt;BR&gt;GO &lt;BR&gt;--SELECT * FROM AlterIndexLoggingData; &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;--- BULK_LOGGED Recovery, ONLINE = ON&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT face=Consolas&gt;BACKUP LOG AdventureWorks TO DISK = 'c:\backups\AW_log.bak' WITH INIT; &lt;BR&gt;SELECT COUNT(*)&amp;nbsp; FROM fn_dblog(null, null); &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;ALTER INDEX&amp;nbsp; CL_details_indx&amp;nbsp; ON Details REBUILD WITH (ONLINE = ON) &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;INSERT INTO AlterIndexLoggingData &lt;BR&gt;SELECT 'BULK_LOGGED', 'ON', &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MAX([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM([Log Record Length]), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COUNT(*), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SELECT COUNT(*) FROM fn_dblog(null, null) WHERE [Log Record Length]&amp;nbsp; &amp;gt; 8000) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM fn_dblog(null, null); &lt;BR&gt;GO &lt;BR&gt;SELECT * FROM AlterIndexLoggingData; &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Here are my results:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/image_7169DDEF.png"&gt;&lt;IMG style="BACKGROUND-IMAGE:none;BORDER-RIGHT-WIDTH:0px;PADDING-LEFT:0px;PADDING-RIGHT:0px;DISPLAY:inline;BORDER-TOP-WIDTH:0px;BORDER-BOTTOM-WIDTH:0px;BORDER-LEFT-WIDTH:0px;PADDING-TOP:0px;" title=image border=0 alt=image src="http://sqlblog.com/blogs/kalen_delaney/image_thumb_16F35B51.png" width=650 height=141&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Notice the following: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Only FULL recovery with an OFFLINE rebuild logged the 8K pages. &lt;/LI&gt;
&lt;LI&gt;FULL recovery with an ONLINE rebuild actually did log every single row; in fact, it looks like at least two log records were generated for each row. There is a LOT of logging for this set of options and by far, the largest amount of log space used. &lt;/LI&gt;
&lt;LI&gt;BULK_LOGGED mode used substantially less log space than FULL, but the difference between ONLINE and OFFLINE is even more pronounced. In FULL recovery, ONLINE used about twice the log space, in BULK_LOGGED, the logging required more than 8 times the space! &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;I'm sure there are more fun facts you can pull out of the results from &lt;EM&gt;fn_dblog&lt;/EM&gt;, but for my first look at the logging differences between ONLINE and OFFLINE index rebuilds, this is what I wanted to know. It's not a complete answer to the student's question, but it does indicate there is a lot more logging with ONLINE index builds, so it should not&amp;nbsp;be surprising if there are a lot more log write waits. And I would assume that switch to BULK_LOGGED recovery could make a noticeable difference. &lt;/P&gt;
&lt;P&gt;I hope this is useful!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;</description></item><item><title>Point-in-time restore of database backup?</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/12/28/point-in-time-restore-of-database-backup.aspx</link><pubDate>Tue, 28 Dec 2010 16:42:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:32051</guid><dc:creator>TiborKaraszi</dc:creator><description>&lt;P&gt;SQL Server 2005 added the STOPAT option for the RESTORE DATABASE command. This sounds great - we can stop at some point in time during the database backup process was running! Or? No, we can't. Here follows some tech stuff why not, and then what the option is really meant&amp;nbsp;for:&lt;/P&gt;
&lt;P&gt;A database backup includes all used extents and also all log records that were produced while the backup process was running (possibly older as well, to handle open transactions). When you restore such a backup, SQL Server will from backup media copy the data pages to mdf and ndf file(s), log records to ldf file(s) and then do REDO (roll forward the log records) and possibly also UNDO (rollback open transactions - this is skipped if you specify NORECOVERY option). Why does it need the log records? Because you can do modifications in the database while the database backup is running. After backup process was started (and before it finishes) you can both modify pages not yet copied to backup media, but also pages already copied to backup media. So, the data pages in themselves do not present a consistent state of the database. At restore time, SQL Server uses the log records included in the database backup to "sync" the modifications that were performed while the backup process were running. So, what you end up with is what the database looked like at the &lt;STRONG&gt;end time&lt;/STRONG&gt; of the backup process. I'm sure this is well documented somewhere in Books Online so I won't dive further into the tech stuff here.&lt;/P&gt;
&lt;P&gt;So, what is the purpose of the STOPAT option for RESTORE DATABASE?&lt;/P&gt;
&lt;P&gt;It is to give you an early warning, in case you try to restore a database backup which is too late for a subsequent STOPAT operation for a log restore. Here's an example:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;13:00 db backup&lt;/LI&gt;
&lt;LI&gt;13:10 log backup&lt;/LI&gt;
&lt;LI&gt;13:20 log backup&lt;/LI&gt;
&lt;LI&gt;13:30 db backup&lt;/LI&gt;
&lt;LI&gt;13:40 log backup&lt;/LI&gt;
&lt;LI&gt;13:50 log backup&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Say you now want to restore to 13:15. Intuitively, you say that you will restore 1, 2 and for 3 you do STOPAT 13:15. Yes, that is right. &lt;/P&gt;
&lt;P&gt;But say you are under stress, and perhaps even used some tool which confuses things for you? So, you end up restore 4, 5 and for 6 you try STOPAT 13:15. Clearly, you can't stopat 13:15 for backup number 6 (it only covers 13:40 to 13:50). I.e., restore of 6 gives you an error message. So, you have to re-start the restore process (1, 2 and 3), which could take a long time (if the backups are large). If you had specified STOPAT 13:15 when you restore backup 4, SQL Server would have given you an error immediately, so you wouldn't have wasted valuable time restoring unnecessary backups! &lt;/P&gt;
&lt;P&gt;That is the purpose of STOPAT for RESTORE DATABASE.&lt;/P&gt;</description></item><item><title>Why we never want to trick SQL Server into rebuilding a log file</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/10/14/why-we-never-want-to-trick-sql-server-into-rebuilding-a-log-file.aspx</link><pubDate>Thu, 14 Oct 2010 17:04:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:29398</guid><dc:creator>TiborKaraszi</dc:creator><description>&lt;P&gt;"Never" is a strong word, so let me say that we really really want to avoid it, if at all humanly possible. In short, we will have a (potentially) broken database, both at the physical level and at the logical level. Read on.&lt;/P&gt;
&lt;P&gt;Just to be clear, when I refer to a "log file" here, I'm talking about a transaction log file, an .ldf file. Ever so often we see in forums how log files are "lost", "disappears" or so. Now, SQL Server relies on the ldf file at startup to bring the database to a consistent state. This is known as "recovery", or "startup recovery". This is pretty well known, I for instance teach this at every intro level admin course. So, what if&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;The ldf file isn't there? &lt;/LI&gt;
&lt;LI&gt;Or isn't accessible to the db engine? &lt;/LI&gt;
&lt;LI&gt;Or is broken somehow? &lt;/LI&gt;
&lt;LI&gt;Or is from a different point in time from the data file? (You'd be surprised to all the things one see over the years.)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Well, SQL Server will do the only reasonable, refuse us into the database and produce an error message (in eventlog etc). &lt;/P&gt;
&lt;P&gt;What we see from time to time, is trying to "trick" SQL Server into re-creating an ldf file. So, why is this so bad? I will try to explain why. Let me first say that SQL Server doesn't do these things to be mean to us, or to prove a point. If SQL Server know that the ldf file is &lt;STRONG&gt;not&lt;/STRONG&gt; necessary for recovery (the database was "cleanly shutdown"), then it can and will re-create a log file for us at startup. The problem is that it isn't these cases we see in forum. The cases we see in the forums is when this &lt;STRONG&gt;didn't&lt;/STRONG&gt; happen. SQL Server relied on the ldf file in order to bring the database to a consistent state. &lt;/P&gt;
&lt;P&gt;Enough beating around the bush, here is an example of why we don't want to trick SQL Server to forcefully re-create a log file:&lt;/P&gt;
&lt;P&gt;Say you have a transaction in which you add a row to the order header table (oh) and five rows to the order details table (od). Physically, each command is reflected in the tlog, the page is modified (but still cached) and at commit, the log records are written to the ldf file. There are lots written about these algorithms, but the concepts are pretty simple. For more details, read &lt;A title=this href="http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/sqlIObasics.mspx"&gt;this&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;Say that we forcefully stop SQL Server, delete the ldf file, start SQL Server, see that the database isn't accessible and somehow "trick" SQL Server into creating an ldf file for us. What is the problem? Why is this so bad? The problem is that you can have no confidence in the state of your data, both at the physical level and at the logical level. Let me start explaining what I mean by the logical level and problems at this level:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The logical level&lt;BR&gt;&lt;/STRONG&gt;By the logical level, I consider the user data. The rows in the tables, quite simply. We inserted one row in the oh table and five rows in the od table. These can be inserted into a total of two pages or 6 pages (in reality more, since each table is likely to have indexes etc, I'll touch on this when we get to the logical level). Say that three of order details rows have been written to disk, but not the order header row, and not the other two order details rows. This is just an example; you can pick and choose any combo you want. It can get just as bad as you can imagine! You might think that the pages are in the end written in the same sequence as we modified them. No, that is now how the cookie crumbles (read the article I posted link to). You can probably imagine other scenarios, closer to your data. For instance, we will not do some certain modification to a table unless some other prior modification was also performed. In essence, rebuilding a log file leave us with no confidence in the data. Are you prepared to go through your database and manually verify all the data in there? Majority of you will say "no", and it might not even be doable (data volumes, lack of information to verify etc). So, logical inconsistencies are bad. Really bad. We don't want this. Ok?&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The physical level&lt;/STRONG&gt;&lt;BR&gt;This log is not only used for "user-data". It i also used for system data. Tables has indexes, where each row in a table is reflected by a row in each index. We have allocation pages stating what storage is used. We have IAM pages and PFS pages. We have linked lists. And whatnot. You probably realize that these structures also require that some modification is performed in full or not at all. (an extent allocation will be reflected in both the GAM or SGAM page and also in th extent data itself, etc). What do you think is used to protect this? Yes, you got it, the ldf file. Trick SQL Server into re-creating an ldf file and you have all sorts of physical inconsistencies. Actually, physical inconsistencies are a bit better than logical since we do have a way to check for these. I'm of course talking about the mighty DBCC CHECKDB command, a command with lots of smarts (right Paul?) to check that the db is consistent at the physical level. And what if it isn't? CHECKDB spits out errors. Sure it has repair options, but those generally mean&amp;nbsp;(unless you are the type of person who wins are lotteries) that the repair will rip out whatever makes the db inconsistent resulting in data loss (which also has no knowledge of what you might consider logical consistent data). &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;So, what to do?&lt;/STRONG&gt;&lt;BR&gt;I hope the answer is obvious. Don't get into this situation in the first place. Don't go deleting ldf files for instance. Do take backups frequently enough so you don't end up in a situation like "I need to rebuild the log or I'm toast.". If something strange happens, don't start mucking about with the system unless you know what you are doing. Hire a specialist, call MS support&amp;nbsp;or so. If I had a brand new Ferrari, I wouldn't&amp;nbsp;disassemble the engine&amp;nbsp;in case I hear weird noise from the it. Heck, I barely pop the hood of my Beamer! &lt;/P&gt;
&lt;P&gt;And no, I won't get into what commands can be used to re-build the ldf file. I expect all readers of this to not get into a situation where it is needed. :-)&lt;/P&gt;
&lt;P&gt;(I understand one can encounter a machine with no backups and something happens to the ldf file, and such scnearios. Of course I do. I feel really really bad every time I read about such a situation, because there is no graceful way to handle it. That is why I have such a&amp;nbsp;harsh tone above. I don't want this to happen to anybody. One would hope that this is obvious, but nothing ever is on the Net. So I've learned. So, please leave such unconstructive comments out of the discussions!)&lt;/P&gt;</description></item><item><title>Restore database to the point of disaster</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/03/27/restore-database-to-the-point-of-disaster.aspx</link><pubDate>Sat, 27 Mar 2010 09:50:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:23796</guid><dc:creator>TiborKaraszi</dc:creator><description>&lt;P&gt;This is really basic, but so often overlooked and misunderstood. Basically, we have a database, and something goes south. Can we restore all the way up to that point? I.e., even if the last backup (db or log) is earlier than the disaster? &lt;BR&gt;Yes, of course we can (unless for more extreme cases, read on), but many don't realize/do that, for some strange reason.&lt;/P&gt;
&lt;P&gt;This blog post was inspired from a thread in the MSDN forums, which exposed just this misunderstanding. Basically the scenario was that they do db backup and only log backup once a day. Now, doing log backup that infrequent is of course a bit weird, but that is beside the point. The point is that you can recover all the way up to the point of disaster. Of course, it depends on what the disaster is (don't expect too much if the planet blows up, for instance).&lt;/P&gt;
&lt;P&gt;Since "log backup only once a day" was mentioned, I will first elaborate a bit on frequency for&amp;nbsp;database vs log&amp;nbsp;backups. For the sake of discussion, say we do both db and log backup once a day. You say:&lt;BR&gt;"What? Both db backup and log backup once a day - why would anybody do that way? Wouldn't one do log backup more frequently than db backup?" &lt;BR&gt;Yes, of course (but I actually see such weird implementations from time to time). But again, that doesn't change the topic at hand, but I will first elaborate on this; just so we don't see blurring comments later arguing this irrelevant argument.&lt;/P&gt;
&lt;P&gt;So, lets first sort out two different cases:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;A) Log backup before the db backup&lt;/STRONG&gt;&lt;BR&gt;1: db backup&lt;BR&gt;...&lt;BR&gt;2: log backup&lt;BR&gt;3: db backup&lt;BR&gt;crash&lt;BR&gt;Here we will use backup 3 when we later will restore.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;B) Db backup before log backup&lt;/STRONG&gt;&lt;BR&gt;1: db backup&lt;BR&gt;...&lt;BR&gt;2: db backup&lt;BR&gt;3:&amp;nbsp;log backup&lt;BR&gt;crash&lt;BR&gt;Here we will use backup 2 and 3 when we later will restore.&lt;/P&gt;
&lt;P&gt;You see that A) and B) are really the same thing? What is relevant is that we have all log records available (in ldf file/log backups)&amp;nbsp;since the db backup we chose to use as starting point for the restore. Actually, for A), we could might as well&amp;nbsp;use backup 1 and 2 (and skip 3)! &lt;/P&gt;
&lt;P&gt;"Hang on", you say, "we're not done yet. What about the modifications since the last log backup! Gotcha!"&lt;BR&gt;No worries, this is where it gets interesting, and &lt;STRONG&gt;below is really the heart of the topic&lt;/STRONG&gt;. Clearly, we need to get the log records out of the ldf file into a log backup (file). If we can do that, then we will call this backup number 4, and use as the last backup for our restore. After doing that restore, we have no data loss! &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;So, how do we produce a log backup after a disaster?&lt;/STRONG&gt;&lt;BR&gt;It depends on the disaster! Let's discuss a few scenarios:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;a) Planet Earth blows up.&lt;/STRONG&gt;&lt;BR&gt;No can do. I doubt that anyone of you has mirrored data centers on Moon or March; and also people stationed off-Earth for these situations. Of course, I'm being silly. But my point is that you can always have a disaster such that you can't produce that last log backup. No matter how much you mirror: if the disaster takes out all mirrors, then you are toast. Remember that when you talk SLA's. That fact is not popular, but it can't be argued. It is all about &lt;STRONG&gt;limiting the risk exposure - not eliminating it&lt;/STRONG&gt;. Anybody who believes we can eliminate risk exposure&amp;nbsp;is dreaming. Agreed? Good. Let's move on to (hopefully) more realistic scenarios:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;b) Something happens with the data file(s), lost, corrupt or so. Ldf file is still there.&lt;/STRONG&gt;&lt;BR&gt;This is the easy case, but so often overlooked. What you do now is to backup the log of the damaged database, using the NO_TRUNCATE option. Something like:&lt;BR&gt;BACKUP LOG dbname TO DISK = 'C:\dbname.trn' WITH NO_TRUNCATE&lt;BR&gt;Yes, it really is that simple. Then restore backups from above, including this last log backup. Don't believe me? Test it. &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Create database and table&lt;/LI&gt;
&lt;LI&gt;Insert some data&lt;/LI&gt;
&lt;LI&gt;Do db backup (1)&lt;/LI&gt;
&lt;LI&gt;Insert some more data&lt;/LI&gt;
&lt;LI&gt;Do log backup (2)&lt;/LI&gt;
&lt;LI&gt;Insert some more data&lt;/LI&gt;
&lt;LI&gt;Stop SQL Server&lt;/LI&gt;
&lt;LI&gt;Delete mdf file&lt;/LI&gt;
&lt;LI&gt;Start SQL Server&lt;/LI&gt;
&lt;LI&gt;Do log backup using NO_TRUNCATE (3)&lt;/LI&gt;
&lt;LI&gt;Restore 1, 2 and 3.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;STRONG&gt;c) Something happens with the database. Ldf file is NOT still there.&lt;/STRONG&gt;&lt;BR&gt;Clearly, if the ldf file is really gone, we can't do a log backup - how much as we might want to. Remember the old days, when redundancy for disks (RAID) wasn't as common as today? "If there's anywhere you want redundancy, it is for the transaction log files!"&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;d) Something happens with the data file(s), lost, corrupt or so. Ldf file is still there. The installation is toast - we can't start SQL Server.&lt;/STRONG&gt;&lt;BR&gt;This seems a bit more nerve-wracking, right? Not to worry, just do the right steps and you will be fine. You probably ask now:&lt;/P&gt;
&lt;P&gt;"But how can we backup the transaction log when our SQL Server won't start?"&lt;/P&gt;
&lt;P&gt;That is a good question. You need to get that ldf file to a healthy SQL Server, and make SQL Server believe this is the ldf file for&amp;nbsp;a broken database on &lt;STRONG&gt;that&lt;/STRONG&gt; instance. It is not really complicated. Just use a dummy database on that SQL Server as intermediate - to get the right meta-data into that SQL Server, so in turn it will allow you to produce this last log backup. I will show just that:&lt;/P&gt;
&lt;P&gt;I have two instances on my machine (named "a" and "b"). I will create and damage a database on instance a, and then produce a log backup for that orphaned ldf file a different instance, b. I will pretend these are on two different machines, using separate folders for the database files "C:\a" and "C:\b". Here's the T-SQL, starting with instance a:&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;IF&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;DB_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'x'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DROP&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x &lt;BR&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON&amp;nbsp;PRIMARY&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'x'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILENAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'C:\a\x.mdf'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;SIZE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;10MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILEGROWTH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;10MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'x_log'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILENAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'C:\a\x_log.ldf'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;SIZE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;5MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILEGROWTH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;5MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ALTER&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;RECOVERY&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FULL &lt;BR&gt;CREATE&amp;nbsp;TABLE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x.dbo.t&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;IDENTITY&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x.dbo.t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT&amp;nbsp;VALUES&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--1 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BACKUP&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x.bak'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;INIT &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x.dbo.t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT&amp;nbsp;VALUES&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--2 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BACKUP&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x1.trn'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;INIT &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x.dbo.t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT&amp;nbsp;VALUES&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--3 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x.dbo.t &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Stop&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;and&amp;nbsp;delete&amp;nbsp;below&amp;nbsp;file &lt;BR&gt;--C:\a\x.mdf &lt;BR&gt;--Start&amp;nbsp;SQL&amp;nbsp;Server &lt;BR&gt;&lt;BR&gt;--Oops,&amp;nbsp;damaged&amp;nbsp;database...: &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x.dbo.t &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Stop&amp;nbsp;SQL&amp;nbsp;Server,&amp;nbsp;pretend&amp;nbsp;installation&amp;nbsp;is&amp;nbsp;toast&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;Do we agree that we have a damaged database, and there has been done modifications since the last log backup? Ok, fine. We now pretend that SQL Server instance "a" doesn't start anymore. So, I will try to produce a log backup from that ldf file on instance "b":&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;IF&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;DB_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'x2'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DROP&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x2 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;DB_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'x'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DROP&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x &lt;BR&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x2 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON&amp;nbsp;PRIMARY&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'x2'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILENAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'C:\b\x2.mdf'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;SIZE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;9MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILEGROWTH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;8MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'x2_log'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILENAME&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'C:\b\x2_log.ldf'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;SIZE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;6MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILEGROWTH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;7MB&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Stop&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;and&amp;nbsp;delete&amp;nbsp;below&amp;nbsp;files &lt;BR&gt;--C:\b\x2.mdf &lt;BR&gt;--C:\b\x2_log.ldf &lt;BR&gt;&lt;BR&gt;--Copy&amp;nbsp;the&amp;nbsp;C:\a\x_log.ldf&amp;nbsp;to&amp;nbsp;C:\b\x2_log.ldf &lt;BR&gt;&lt;BR&gt;--Start&amp;nbsp;SQL&amp;nbsp;Server &lt;BR&gt;&lt;BR&gt;--Produce&amp;nbsp;our&amp;nbsp;last&amp;nbsp;log&amp;nbsp;backup: &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BACKUP&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x2&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x2.trn'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;INIT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NO_TRUNCATE &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Restore&amp;nbsp;the&amp;nbsp;database,&amp;nbsp;up&amp;nbsp;to&amp;nbsp;last&amp;nbsp;transaction. &lt;BR&gt;--Investigate&amp;nbsp;logical&amp;nbsp;file&amp;nbsp;names&amp;nbsp;for&amp;nbsp;MOVE&amp;nbsp;options&amp;nbsp;first: &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RESTORE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FILELISTONLY&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x.bak'&amp;nbsp; &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RESTORE&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x.bak'&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH &lt;BR&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NORECOVERY &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;MOVE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'x'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;TO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\b\x.mdf' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;MOVE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'x_log'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;TO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\b\x_log.ldf' &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RESTORE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x1.trn'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NORECOVERY &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RESTORE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x2.trn'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;RECOVERY &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Data&amp;nbsp;there? &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x.dbo.t &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--See?&amp;nbsp;That&amp;nbsp;wasn't&amp;nbsp;so&amp;nbsp;difficult.&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;Note how I even named the dummy database differently on instance b, with different physical file names and different file sizes (all compared to what we had on instance a). Typically, you will use same database name and same filename, but I want to show that we don't really have to know a whole lot about the damaged database in order to produce a log backup from the ldf file!&lt;/P&gt;
&lt;P&gt;Case closed.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp;&lt;/P&gt;</description></item><item><title>Are log records removed from ldf file for rollbacks?</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/03/22/are-log-records-removed-from-ldf-file-for-rollbacks.aspx</link><pubDate>Mon, 22 Mar 2010 09:34:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:23627</guid><dc:creator>TiborKaraszi</dc:creator><description>&lt;P&gt;Seems like a simple enough question, right? This question (but more targeted, read on) was raised in an MCT forum. While the discussion was on-going and and I tried to come up with answers, I realized that this question are really several questions. First, what is a rollback? I can see three different types of rollbacks (there might be more, of course):&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Regular rollback, as in ROLLBACK TRAN (or lost/terminated connection)&lt;/LI&gt;
&lt;LI&gt;Rollback done by restore recovery. I.e., end-time of backup included some transaciton which wasn't committed and you restore using RECOVERY, so SQL Server need to rollback this transaction (UNDO).&lt;/LI&gt;
&lt;LI&gt;Rollback done by crash (restart) recovery. I.e. SQL Server was shut down with some open transaction.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;I'm going to try to show whether log records are removed or still present for these three types of rollback situations. I will use the fn_dblog function. This isn't documented or supported, but search the internet and you will find how to use it. The result isn't documented either, of course, so we have to guess a bit what the various values mean...&lt;/P&gt;
&lt;P&gt;The TSQL script has some common parts (the same part executed repeatedly, once for each test):&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Create a database&lt;/LI&gt;
&lt;LI&gt;Make sure it is in full recovery&lt;/LI&gt;
&lt;LI&gt;Do a database backup&lt;/LI&gt;
&lt;LI&gt;Create a table (myTable)&lt;/LI&gt;
&lt;LI&gt;Insert a row into myTable. This last operation generates 5 log records for the myTable table: one for the PFS page, two for IAM pages, one format page for the heap and the last one is&amp;nbsp;a LOP_INSERT_ROWS. &lt;/LI&gt;
&lt;LI&gt;Start a transaction&lt;/LI&gt;
&lt;LI&gt;Insert one more row into myTable. We now have one more log record for myTable (LOP_INSERT_ROWS). Looking at the transaction id for this last insert, we see two log records (one LOP_BEGIN_XACT and the LOP_INSERT_ROWS). Note that this transaction is now open!&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Here is the above mentioned first part of the script:&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;USE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;master &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;DB_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'x'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DROP&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x &lt;BR&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x &lt;BR&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ALTER&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;RECOVERY&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FULL &lt;BR&gt;BACKUP&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x.bak'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;INIT &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;USE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;TABLE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;myTable&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;IDENTITY&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;myTable&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT&amp;nbsp;VALUES &lt;BR&gt;&lt;BR&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--5&amp;nbsp;rows &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN&amp;nbsp;TRAN &lt;BR&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;myTable&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT&amp;nbsp;VALUES &lt;BR&gt;&lt;BR&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--6&amp;nbsp;rows &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;TOP&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp; &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL) &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ORDER&amp;nbsp;BY&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Current&amp;nbsp;LSN]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DESC&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--2&amp;nbsp;rows&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;Now, on to the different&amp;nbsp;cases:&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;1. Regular rollback, as in ROLLBACK TRAN.&lt;BR&gt;&lt;/STRONG&gt;It seems reasonable to me that SQL Server will just add some "rollback transaction" log record here. So, let's try that (continuing on above first part)... We now have 7 log records for myTable, with&amp;nbsp;an&amp;nbsp;added&amp;nbsp;LOP_DELETE_ROWS which undo the previously insert. And for our transaction ID, we have 4 rows, with added two rows being LOP_DELETE_ROWS (compensation log record)&amp;nbsp;and a LOP_ABORT_XACT. &lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:green;"&gt;--Regular&amp;nbsp;ROLLBACK &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&amp;nbsp;TRAN &lt;BR&gt;&lt;BR&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--7&amp;nbsp;rows &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;TOP&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp; &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL) &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ORDER&amp;nbsp;BY&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Current&amp;nbsp;LSN]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DESC&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--4&amp;nbsp;rows&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;&lt;STRONG&gt;2. Restore recovery&lt;BR&gt;&lt;/STRONG&gt;Now, what does this really mean? Restoring a transaction log backup is a good example. SQL Server read log records from the transaction log backup file and writes them into the LDF file. This is what we call the "data copy" phase. Then SQL Server performs REDO (a.k.a. roll forward). And finally, SQL Server performs UNDO (roll back), assuming we don't do the restore using the NORECOVERY option. Restoring from a database backup isn't any differene except the log records are of course read from&amp;nbsp;the database backup file.&lt;/P&gt;
&lt;P&gt;Here it seems likely that SQL Server will wipe more or less anything from the LDF file as soon as the database is restored and brought on-line. Why? The log in this newly restored database can't serve as a starting point for a restore operation for this database. You first need a database backup. So, no use hanging onto log records either! Let's see if we can verify that:&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:green;"&gt;--Restore&amp;nbsp;recovery &lt;BR&gt;&lt;BR&gt;--Do&amp;nbsp;this&amp;nbsp;from&amp;nbsp;different&amp;nbsp;connection &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BACKUP&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x.bak' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--We&amp;nbsp;now&amp;nbsp;have&amp;nbsp;open&amp;nbsp;transaction&amp;nbsp;in&amp;nbsp;database! &lt;BR&gt;&lt;BR&gt;--Perform&amp;nbsp;RESTORE &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK &lt;BR&gt;USE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;master &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RESTORE&amp;nbsp;DATABASE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x.bak'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;REPLACE&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NORECOVERY &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RESTORE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;LOG&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'C:\x.bak'&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;FILE&amp;nbsp;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;2&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;RECOVERY &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Rollback&amp;nbsp;was&amp;nbsp;done,&amp;nbsp;and&amp;nbsp;database&amp;nbsp;berought&amp;nbsp;online.&amp;nbsp; &lt;BR&gt;--What&amp;nbsp;log&amp;nbsp;records&amp;nbsp;do&amp;nbsp;we&amp;nbsp;have? &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--0&amp;nbsp;rows &lt;BR&gt;&lt;BR&gt;--Use&amp;nbsp;the&amp;nbsp;transaction&amp;nbsp;ID&amp;nbsp;from&amp;nbsp;earlier&amp;nbsp;SELECT &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'0000:00000203' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--0&amp;nbsp;rows&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;So, SQL Server will remove user-defined stuff from LDF file after restore recovery was performed. Makes sense.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;3. Crash recovery (a.k.a. restart or startup recovery)&lt;BR&gt;&lt;/STRONG&gt;I couldn't really guess here. So, lets give it a spin immediately and see:&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:green;"&gt;--Crash&amp;nbsp;recovery &lt;BR&gt;&lt;BR&gt;--Do&amp;nbsp;below&amp;nbsp;from&amp;nbsp;separate&amp;nbsp;connection &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;SHUTDOWN&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NOWAIT &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--&amp;nbsp;startup&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;and&amp;nbsp;examine&amp;nbsp;the&amp;nbsp;log&amp;nbsp;records: &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--5&amp;nbsp;rows &lt;BR&gt;&lt;BR&gt;--Use&amp;nbsp;the&amp;nbsp;transaction&amp;nbsp;ID&amp;nbsp;from&amp;nbsp;earlier&amp;nbsp;SELECT &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'0000:00000204' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--0&amp;nbsp;rows&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;Hmm, so SQL Server removes the log record after the rollback was performed. Makes sense. &lt;/P&gt;
&lt;P&gt;But this got me thinking some more. How can this be done... physically? SQL Server would just "reverse" the head of the log a bit. But what if we have later transactions for other connections, which has been committed? SQL Server can't ignore those, of course. These need to be kept in the LDF file for subsequent log backups. OTOH, I doubt that SQL Server will somehow physically delete things "in the middle" of an ldf file. Time for yet another test:&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:green;"&gt;--Crash&amp;nbsp;recovery,&amp;nbsp;part&amp;nbsp;two &lt;BR&gt;&lt;BR&gt;--Do&amp;nbsp;below&amp;nbsp;from&amp;nbsp;separate&amp;nbsp;connection &lt;BR&gt;--First&amp;nbsp;something&amp;nbsp;which&amp;nbsp;creates&amp;nbsp;more&amp;nbsp;recent&amp;nbsp;log&amp;nbsp;records &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;TABLE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;y&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;y&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;SHUTDOWN&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NOWAIT &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--&amp;nbsp;startup&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;and&amp;nbsp;examine&amp;nbsp;the&amp;nbsp;log&amp;nbsp;records: &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--7&amp;nbsp;rows &lt;BR&gt;&lt;BR&gt;--Use&amp;nbsp;the&amp;nbsp;transaction&amp;nbsp;ID&amp;nbsp;from&amp;nbsp;earlier&amp;nbsp;SELECT &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL)&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;TOP&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Transaction&amp;nbsp;ID]&amp;nbsp; &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;fn_dblog&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(NULL,&amp;nbsp;NULL) &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AllocUnitName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;LIKE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'%myTable%' &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;&amp;nbsp;&amp;nbsp;&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;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ORDER&amp;nbsp;BY&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[Current&amp;nbsp;LSN]&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DESC&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--4&amp;nbsp;rows&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;Now the log records for our rolled back transaction are still there! So, just as when we did a regular rollback, SQL Server inserted a LOP_DELETE_ROWS to reflect the undo of the INSERT, and then a LOP_ABORT_XACT.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Conclusion&lt;/STRONG&gt;&lt;BR&gt;Isn't it beautiful when it all makes sense? Here are my conclusions, whether log records are kept or removed from transaction log file (LDF) for various types of rollback scenarios:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV&gt;Regular rollback. Log records are not removed. Compensation log records are logged, reflecting undo of the modifications, and then an LOP_ABORT_XACT is logged.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Restore recovery. Log records are removed.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Crash recovery. It depdends. If you have a transaction which is at the very head of the log, then those log records can be removed. If there are other, subsequent committed transactions, then compensation log records are logged, reflecting undo of the modifications, and then a LOP_ABORT_XACT is logged.&lt;BR&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;</description></item><item><title>Geek City: Exploring the Transaction Log Structure</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2009/12/21/exploring-the-transaction-log-structure.aspx</link><pubDate>Tue, 22 Dec 2009 00:48:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:20158</guid><dc:creator>Kalen Delaney</dc:creator><description>&lt;P&gt;As I mentioned last October, my PASS preconference seminar was a &lt;A href="http://sqlblog.com/blogs/kalen_delaney/archive/2009/10/31/a-whole-day-of-transaction-log-info.aspx" target=_blank&gt;whole day about the transaction log&lt;/A&gt;. I told the attendees all kinds of things about the structure of the log, and told them about one of the best tools for exploring the structure: the command DBCC LOGINFO. This command is officially undocumented, but numerous bloggers have discussed it in some detail, including &lt;A href="http://www.mssqltips.com/tip.asp?tip=1225" target=_blank&gt;here&lt;/A&gt;. I'm not going to go into all the details here, but I'll be writing some related blog posts over the next month or so.&amp;nbsp; To understand DBCC LOGINFO you need to know about VLFs (Virtual Log Files) and one of the best places to read about VLFs is in &lt;A href="http://technet.microsoft.com/en-us/magazine/2009.02.logging.aspx" target=_blank&gt;Paul Randal's TechNet article&lt;/A&gt;. The DBCC LOGINFO command returns one row per VLF including the following columns:&lt;/P&gt;
&lt;P&gt;FileId &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;If you only have one physical log file, this value will be the same in every row. If you have multiple log files, you can use this value to explore the order that the SQL Server will fill up VLFs in multiple files. (More details in a future post.)&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;FileSize&amp;nbsp; &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;This value is in bytes. If you have your log file growth set to a percentage (which, unfortunately is the default), you should notice this value getting progressively larger as more VLFs are added to your log file.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;StartOffset &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;This value is also in bytes, and is used as the sort column for the output. That is, the output from DBCC LOGINFO (if you only have single physical file) will be ordered by StartOffset. Notice that the first VLF always starts at offset 8192, which is the number of bytes in a page. The first page of the physical file is the file header, and does not store log records.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;FSeqNo &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;The File Sequence Number indicates the order of usage of the VLFs. The row with the highest FSeqNo value is the VLF where current log records are being written. Notice that the FSeqNo values are not always consistent with the StartOffset, as VLFs are reusable after the log has been truncate. I'll discuss this value more in a future post, or you can get some info from Paul's article on how and when a VLF is reused. A value of 0 for the FSeqNo means that this VLF has never been used at all yet.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Status &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;Status has two possible values: 0 and 2. I'll be discussing these values in a lot more detail later. For now, the simple definition is that a value of 2 means the VLF is not reusable and a value of 0 means it is.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;BR&gt;Parity &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;Parity has two possible values: 64 and 128. Every time a VLF is reused, the parity value is switched. Paul Randal discusses the parity value in more detail in &lt;/EM&gt;&lt;A href="http://www.sqlskills.com/BLOGS/PAUL/post/Search-Engine-QA-24-Why-cant-the-transaction-log-use-instant-initialization.aspx" target=_blank&gt;&lt;EM&gt;this article.&lt;/EM&gt;&lt;/A&gt;&lt;EM&gt; &lt;BR&gt;&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;CreateLSN &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;This value indicates when the VLF was created. If the CreateLSN is 0, it means the VLF was original equipment, created when the database was created. You can use this value to see how many VLFs were added each time the log grew. VLFs with the same CreateLSN value were created at the same time. &lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The whole point of describing all these columns was just to provide a lead-in to my little holiday gift to you. Here is a table that can be created in the master database, and then populated with the output of DBCC LOGINFO. The name of the table starts with sp_, which means you can use it from any database.&amp;nbsp; Once you have captured all the rows from DBCC LOGINFO, you can query them using any TSQL queries.&lt;/P&gt;
&lt;P&gt;Here the table creation script:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=1 face="Courier New"&gt;USE master &lt;BR&gt;GO &lt;BR&gt;IF EXISTS&amp;nbsp; (SELECT 1 FROM sys.tables &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; WHERE name = 'sp_LOGINFO') &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP TABLE sp_loginfo; &lt;BR&gt;GO &lt;BR&gt;CREATE TABLE sp_LOGINFO &lt;BR&gt;(FileId tinyint, &lt;BR&gt;FileSize bigint, &lt;BR&gt;StartOffset bigint, &lt;BR&gt;FSeqNo int, &lt;BR&gt;Status tinyint, &lt;BR&gt;Parity tinyint, &lt;BR&gt;CreateLSN numeric(25,0) ); &lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;And here is how to populate it. I will use the &lt;EM&gt;AdventureWorks&lt;/EM&gt; database for the example:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=1 face="Courier New"&gt;USE AdventureWorks; &lt;BR&gt;GO &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=1 face="Courier New"&gt;TRUNCATE TABLE sp_LOGINFO; &lt;BR&gt;INSERT INTO sp_LOGINFO &lt;BR&gt;&amp;nbsp;&amp;nbsp; EXEC ('DBCC LOGINFO');&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;You can select the VLFs from most recently used to the least:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT size=1 face="courier new"&gt;SELECT * FROM sp_LOGINFO &lt;BR&gt;ORDER BY FSeqNo DESC;&lt;/FONT&gt; &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;You can count how many VLFs have each status value:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=1 face="Courier New"&gt;SELECT status, COUNT(*) FROM sp_LOGINFO &lt;BR&gt;GROUP BY status;&lt;/FONT&gt; &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;If you don't have a lot of VLFs, you can try to generate more by running SELECT INTO repeatedly. Make sure you are in FULL recovery to get the most log growth:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=1 face="Courier New"&gt;SELECT * INTO dbo.Orders FROM AdventureWorks.Sales.SalesOrderDetail; &lt;BR&gt;DROP TABLE dbo.Orders; &lt;BR&gt;GO 5&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT size=1 face="Courier New"&gt;TRUNCATE TABLE sp_LOGINFO; &lt;BR&gt;INSERT INTO sp_LOGINFO &lt;BR&gt;&amp;nbsp;&amp;nbsp; EXEC ('DBCC LOGINFO');&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT size=1 face="Courier New"&gt;SELECT status, COUNT(*) FROM sp_LOGINFO &lt;BR&gt;GROUP BY status WITH ROLLUP;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;You may be able to figure out other queries that provide useful or interesting information for you. I'll refer back to this table in my future discussions on DBCC LOGINFO and VLFs.&lt;/P&gt;
&lt;P&gt;Enjoy!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;</description></item></channel></rss>