<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>SQL Server Storage Engine : DBCC</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx</link><description>Tags: DBCC</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Example corrupt database to play with and some backup/restore things to try</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2007/04/17/example-corrupt-database-to-play-with.aspx</link><pubDate>Tue, 17 Apr 2007 20:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2164515</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/2164515.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=2164515</wfw:commentRss><description>&lt;P&gt;I've been asked several times over the last few weeks for an example corrupt database to play with, and for testing logic built around DBCC CHECKDB.&lt;/P&gt;
&lt;P&gt;The attached WinZip file contains a backup of a simple 2005 database called 'broken' (I can do a 2000 one too if there's enough demand). It has a simple table called 'brokentable' (c1 int, c2 varchar(7000)) with one row in it. The table has a single data page with page ID (1:143) that I've corrupted so the page checksum is corrupt.&lt;/P&gt;
&lt;P&gt;This means you can try all sorts of cool things. Below I've listed a few things you can try out to see what would happen on &lt;EM&gt;your&lt;/EM&gt; database if a checksum failed.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Restore&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;I didn't do anything special when backing up this database so restoring works just fine, even though it contains a corrupt page.&lt;FONT color=#0000ff size=2&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; broken &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken.bck'&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;MOVE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'broken'&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken.mdf'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;MOVE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'broken_log'&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken_log.ldf'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;Processed 160 pages for database 'broken', file 'broken' on file 1.&lt;/P&gt;
&lt;P&gt;Processed 2 pages for database 'broken', file 'broken_log' on file 1.&lt;/P&gt;
&lt;P&gt;RESTORE DATABASE successfully processed 162 pages in 0.314 seconds (4.203 MB/sec).&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;DBCC CHECKDB&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;CHECKDB throws us some nice errors:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; CHECKDB &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'broken'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; NO_INFOMSGS&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; ALL_ERRORMSGS&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Msg 8928, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Object ID 2073058421, index ID 0, partition ID 72057594038321152, alloc unit ID 72057594042318848 (type In-row data): Page (1:143) could not be processed. See other errors for details.&lt;/P&gt;
&lt;P&gt;Msg 8939, Level 16, State 98, Line 1&lt;/P&gt;
&lt;P&gt;Table error: Object ID 2073058421, index ID 0, partition ID 72057594038321152, alloc unit ID 72057594042318848 (type In-row data), page (1:143). Test (IS_OFF (BUF_IOERR, pBUF-&amp;gt;bstat)) failed. Values are 12716041 and -4.&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 2 consistency errors in table 'brokentable' (object ID 2073058421).&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 2 consistency errors in database 'broken'.&lt;/P&gt;
&lt;P&gt;repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (broken).&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;STRONG&gt;Query errors&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Any query that touches that page is going to fail with an 824 error:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SELECT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;*&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; broken&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;..&lt;/FONT&gt;&lt;FONT size=2&gt;brokentable&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Msg 824, Level 24, State 2, Line 1&lt;/P&gt;
&lt;P&gt;SQL Server detected a logical consistency-based I/O error: incorrect checksum (expected: 0x7232c940; actual: 0x720e4940). It occurred during a read of page (1:143) in database ID 8 at offset 0x0000000011e000 in file 'c:\broken.mdf'. Additional messages in the SQL Server error log or system event log may provide more detail. This is a severe error condition that threatens database integrity and must be corrected immediately. Complete a full database consistency check (DBCC CHECKDB). This error can be caused by many factors; for more information, see SQL Server Books Online.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;STRONG&gt;Backup with CHECKSUM&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;If you have page checksums turned on, you should always use the WITH CHECKSUM option on backups to validate the page checksums as they are read:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;BACKUP&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; broken &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken2.bck'&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;CHECKSUM&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Msg 3043, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;BACKUP 'broken' detected an error on page (1:143) in file 'c:\broken.mdf'.&lt;/P&gt;
&lt;P&gt;Msg 3013, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;BACKUP DATABASE is terminating abnormally.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;But we can force it to backup. If this is the only copy of the database we have, and we're being forced to run repair, for instance, then we want to make sure we have a backup to restore from. Even a backup that contains a corrupt database is better than no database at all. In this case, we need to use the CONTINUE_AFTER_ERROR option.&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;BACKUP&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; broken &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken2.bck'&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;CHECKSUM&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; CONTINUE_AFTER_ERROR&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Processed 160 pages for database 'broken', file 'broken' on file 1.&lt;/P&gt;
&lt;P&gt;Processed 1 pages for database 'broken', file 'broken_log' on file 1.&lt;/P&gt;
&lt;P&gt;BACKUP WITH CONTINUE_AFTER_ERROR successfully generated a backup of the damaged database. Refer to the SQL Server error log for information about the errors that were encountered.&lt;/P&gt;
&lt;P&gt;BACKUP DATABASE successfully processed 161 pages in 2.025 seconds (0.651 MB/sec).&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;STRONG&gt;RESTORE VERIFYONLY&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Now that we have a backup that has checksum information in it, let's see how we can check whether the backup is valid:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; VERIFYONLY &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken2.bck'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT size=2&gt;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;&lt;FONT size=1&gt;The backup set was written with damaged data by a BACKUP WITH CONTINUE_AFTER_ERROR.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;Isn't that cool? It tells us that the backup was already corrupt when it was written. Ok - let's ask it to specifically check the checksums in the backup:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; VERIFYONLY &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken2.bck'&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;CHECKSUM&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;The backup set was written with damaged data by a BACKUP WITH CONTINUE_AFTER_ERROR.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;Same&amp;nbsp;thing. What about if we try to check the checksums on the initial backup?&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; VERIFYONLY &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken.bck'&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;CHECKSUM&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Msg 3187, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;RESTORE WITH CHECKSUM cannot be specified because the backup set does not contain checksum information.&lt;/P&gt;
&lt;P&gt;Msg 3013, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;VERIFY DATABASE is terminating abnormally.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;STRONG&gt;RESTORE&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;How about we try to overwrite the existing 'broken' database with the one from the second backup that has checksum information in it?&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; broken &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken2.bck'&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLACE&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;Msg 3183, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;RESTORE detected an error on page (1:143) in database "broken" as read from the backup set.&lt;/P&gt;
&lt;P&gt;Msg 3013, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;RESTORE DATABASE is terminating abnormally.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;/FONT&gt;It won't let us because the backup contains corrupt data. But we can force it if we need to with CONTINUE_AFTER_ERROR again.&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; broken &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c:\broken2.bck'&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLACE&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; CONTINUE_AFTER_ERROR&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Processed 160 pages for database 'broken', file 'broken' on file 1.&lt;/P&gt;
&lt;P&gt;Processed 1 pages for database 'broken', file 'broken_log' on file 1.&lt;/P&gt;
&lt;P&gt;The backup set was written with damaged data by a BACKUP WITH CONTINUE_AFTER_ERROR.&lt;/P&gt;
&lt;P&gt;RESTORE WITH CONTINUE_AFTER_ERROR was successful but some damage was encountered. Inconsistencies in the database are possible.&lt;/P&gt;
&lt;P&gt;RESTORE DATABASE successfully processed 161 pages in 0.392 seconds (3.364 MB/sec).&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;Isn't that cool? It works BUT it tells us that the backup set contained corrupt data and that the database was restored but could have corrupt data in.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Summary&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Have a play about with this database to familiarize yourself with the kind of responses you'll get from the various tools when a corruption exists, and how to work around it if need be. Let me know if you want to see any particular kinds of corruptions explored, or want a database with something specific corrupted in.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Ok - this turned into a longer post than I originally planned :-)&lt;/P&gt;
&lt;P mce_keep="true"&gt;(PS - about 20 people have offered to fill in my VLDB maintenance survey so far - would be great to have some more. The DVD I'm giving as a reward has a bunch of great hands-on labs, including one that does cool backup/restore stuff to work around disasters. See the previous few posts for details. Thanks.)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2164515" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/sqlserverstorageengine/attachment/2164515.ashx" length="153494" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category></item><item><title>Oh no – my backup is corrupt too! Help!</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2007/03/05/oh-no-my-backup-is-corrupt-too-help.aspx</link><pubDate>Tue, 06 Mar 2007 00:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1812450</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/1812450.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=1812450</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Funny how a bunch of people all seem to have the same problem at the same time. Maybe it’s just that people don’t want to talk about corruption until someone else does – it’s like a dark secret that once let out of the bag – everyone talks. The common HA/DR issue over the last few days on the newsgroups and forums seems to be not just data corruption but backup corruption too.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;It goes back to the statement that &lt;EM&gt;you don’t have a backup until you’ve done a restore&lt;/EM&gt;. What do I mean by that? I don’t mean you need to restore it back over the original database, but unless you’ve checked the validity of the backup, how do you know it’s going to work in a disaster recovery situation?&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;You really want to check two things:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;The integrity of the database being backed up&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;The integrity of the backup file itself&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Check #1 is easy – run some form of DBCC consistency checks &lt;STRONG&gt;before&lt;/STRONG&gt; taking a full backup – otherwise you may be backing up a corrupt database. In fact, I was just dealing with a customer who unfortunately had PFS page header corruption (which cannot be repaired through DBCC) in their database and then found out that it was also in their backup. Their choice then became restoring from a week-old backup or exporting all data into a new database – neither of which is particularly palatable…&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Sometimes it may not be possible to run CHECKDB on the source database - commonly on VLDB systems or system with high, continuous workload where the extra overhead required cannot be tolerated for the length of the CHECKDB. In that case, consider running CHECKDB on a restored copy of the database. This not only proves to you that the backup is valid (because it restores correctly) but that the source database was not corrupt at the time the backup was taken. This is a common strategy on systems that where CHECKDB cannot be run. The only problem with this approach is – what does it mean if the CHECKDB comes back with errors? You can’t tell whether the restored database or the source database is corrupt so you’re &lt;EM&gt;forced&lt;/EM&gt; to go back to the source database and run another CHECKDB. Either way – you’ve successfully caught some corruption before it has a chance to really bite you.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;I’ve just explained a component of check #2 – validating the backup. The other thing to do before doing the backup in SQL Server 2005 is choosing to use the WITH CHECKSUM option on the backup command. This will do two things while the backup is being taken:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Evaluate and check all existing page checksums or torn-page protection on database pages as they’re read&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Calculate a checksum over the whole backup stream and save it in the backup&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;This can help ensure that the database being backed up doesn’t have any corruption caused by the IO-subsystem.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Once the backup is taken, it’s possible to verify all of this without actually writing out anything – using RESTORE … WITH VERIFYONLY. This will do everything short of writing bytes to disk, including rechecking any existing page checksums or torn-page protection on pages in the backup and recalculating and checking the checksum on the entire backup.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;So, there’s a lot you can do to cut down on the likelihood of having a corrupt backup when the time comes to use it. Now – what happens if you get into the situation from the title of this post – the database AND the backup are corrupt?&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Well, many people would throw up their hands in despair, but there is one thing you can do – allow the restore to ignore errors. There’s an option on restore called CONTINUE_AFTER_ERROR which will let the restore continue even if page checksum failure or corruptions in the backup stream are found. The catch is that the database may be inconsistent afterwards so you’ll need to work out what data is corrupt and do an export/import or run repair. In the best scenario, the only corruptions needing repair will be in non-clustered indexes, in which case you can rebuild them or allow repair to fix them up. In the worst scenario, the corruptions will be in the base table data, you’ll need to use REPAIR_ALLOW_DATA_LOSS; however, this may still be better than not being able to restore the backup at all.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;Bottom line – make sure you validate your backups after you take them so you don’t get into a difficult situation. Also, be sure to keep more than one business cycle’s worth of backups (not just the last week – but maybe the last month) so that if a backup becomes bad later (through tape degradation, etc), you will have other options for restore and recovery.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1812450" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Backup/default.aspx">Backup</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Restore/default.aspx">Restore</category></item><item><title>How long does *your* CHECKDB take?</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2007/02/13/how-long-does-your-checkdb-take.aspx</link><pubDate>Tue, 13 Feb 2007 07:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1666207</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/1666207.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=1666207</wfw:commentRss><description>&lt;P&gt;Following on from my post a couple of weeks ago (&lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2007/01/24/how-long-will-checkdb-take-to-run.aspx"&gt;https://blogs.msdn.com/sqlserverstorageengine/archive/2007/01/24/how-long-will-checkdb-take-to-run.aspx&lt;/A&gt;), I'm very interested to know how long it takes for your CHECKDBs to run, so I can get an idea of the distribution of run-times on various kinds of hardware for various size databases.&lt;/P&gt;
&lt;P&gt;So, if you have a couple of minutes, I'd be grateful if you could c&amp;amp;p the following into an email to me, &lt;A href="mailto:prandal@microsoft.com"&gt;prandal@microsoft.com&lt;/A&gt;, and answer the questions for one or more of your databases. I'd especially like to hear from those of you who work for Microsoft and look after multiple customers. If I get a worthwhile number of responses (say 100 or so) then I'll collate the responses and post a summary. I'd love to hear about databases larger than 1TB.&lt;/P&gt;
&lt;P&gt;For the&amp;nbsp;first 10 Microsoft and the first 10 non-Microsoft people to respond, I'll send you the Always-On DVD loaded with Hands-On Labs that walk you through a bunch of the various HA/DR technologies. (I'll let you know whether you win and you need to send me your address).&lt;/P&gt;
&lt;P&gt;Many thanks!&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;How large is the database?&lt;/LI&gt;
&lt;LI&gt;What's the size of the largest table?&lt;/LI&gt;
&lt;LI&gt;Do you have any indexed views?&lt;/LI&gt;
&lt;LI&gt;Which command do you run, including options?&lt;/LI&gt;
&lt;LI&gt;How long does the command take to run?&lt;/LI&gt;
&lt;LI&gt;How often do you run it?&lt;/LI&gt;
&lt;LI&gt;Which version &amp;amp; edition of SQL Server are you running?&lt;/LI&gt;
&lt;LI&gt;(If SQL Server 2005, did you notice an increase or decrease in runtime?)&lt;/LI&gt;
&lt;LI&gt;How many CPUs/cores does the server have?&lt;/LI&gt;
&lt;LI&gt;How much memory does the server have?&lt;/LI&gt;
&lt;LI&gt;What platform is the server?&lt;/LI&gt;
&lt;LI&gt;Describe your IO subsystem?&lt;/LI&gt;
&lt;LI&gt;Any comments?&lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1666207" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category></item><item><title>CHECKDB (Part 8): Can repair fix everything?</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2007/02/04/checkdb-part-8-did-repair-fix-everything.aspx</link><pubDate>Sun, 04 Feb 2007 19:53:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1598373</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/1598373.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=1598373</wfw:commentRss><description>&lt;P&gt;I was teaching at a Microsoft-internal class last week and there was a discussion on what corruptions can't be repaired using DBCC. At the same time, several threads popped up on forums and newsgroups with people hitting some of this unrepairable corruptions so I thought that would make a good topic for the next post in the CHECKDB series.&lt;/P&gt;
&lt;P&gt;Before anyone takes this the wrong&amp;nbsp;way - what do I mean by&amp;nbsp;"can't be repaired"? Remember that that purpose of repair is to make the database structurally consistent, and that to do this usually means deleting the corrupt data/structure (that's why the option to do this was aptly named REPAIR_ALLOW_DATA_LOSS - see &lt;A class="" href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/16/633645.aspx" mce_href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/16/633645.aspx"&gt;this post&lt;/A&gt; for more explanation on why repair can be bad). A corruption is deemed unrepairable when it doesn't make sense to repair it given the damage the repair would cause, or the corruption is so rare and so complicated to repair correctly that it's not worth the engineering effort to provide a repair. Remember also that &lt;U&gt;recovery from corruptions should be based on a sound backup strategy&lt;/U&gt;, not on running repair, so making this trade-off in functionality makes perfect sense.&lt;/P&gt;
&lt;P&gt;Here's a few of the more common unrepairable corruptions that people run into along with the reasons they can't be repaired by DBCC.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;PFS page header corruption&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;An example of this is on SQL Server 2005:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;Msg 8946, Level 16, State 12, Line 1&lt;BR&gt;Table error: Allocation page (1:13280496) has invalid PFS_PAGE page header values.&lt;BR&gt;Type is 0. Check type, alloc unit ID and page ID on the page.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;CHECKDB uses the PFS pages to determine which pages are allocated - and so which pages to read to drive the various consistency checks. The only repair for a PFS page is to reconsutruct it - they can't simply be deleted as they're a fixed part of the fabric of the database. PFS pages cannot be rebuilt because there is no infallible way to determine which pages are allocated or not. There are various algorithms I've experimented with to rebuild them with optimistic or pessimistic setting of page allocation statuses and then re-run the various consisteny checks to try to sort out the incorrect choices, but they all require very long run-times. Given the frequency with which we see these corruptions, and the engineering effort required to come up with an (imperfect) solution, I made the choice to leave this as unrepairable.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Critical system table clustered-index leaf-page corruption&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;An example of this is on SQL Server 2000:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;Server: Msg 8966, Level 16, State 1, Line 1&lt;BR&gt;Could not read and latch page (1:18645) with latch type SH. sysindexes failed.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;And on SQL Server 2005:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;&lt;FONT size=1&gt;Msg 7985, Level 16, State 2, Server SUNART, Line 1&lt;BR&gt;System table pre-checks: Object ID 4. Could not read and latch page (1:51) with&lt;BR&gt;latch type SH. Check statement terminated due to unrepairable error.&lt;/FONT&gt;&lt;FONT size=1&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;In a &lt;A class="" href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/19/636410.aspx" mce_href="https://blogs.msdn.com:443/sqlserverstorageengine/archive/2006/06/19/636410.aspx"&gt;previous post&lt;/A&gt; I described why how and why we do special checks of the clustered indexes of the critical system tables. If any of the pages at the leaf-level of these indexes are corrupt, we cannot repair them. Repairing would mean deallocating the page, wiping out the most important metadata for potentially hundreds of user tables and so effectively deleteing all of these tables. That's obviously an unpalatable repair for anyone to allow and so we don't do it.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Column value&amp;nbsp;corruption&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Here's an example of this on SQL Server 2005:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;Msg 2570, Level 16, State 3, Line 1&lt;BR&gt;Page (1:152), slot 0 in object ID 2073058421, index ID 0, partition ID 72057594038321152, alloc unit ID 72057594042318848 (type "In-row data"). Column "c1" value is out of range for data type "datetime".&amp;nbsp; Update column to a legal value.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;This is where a column has a stored value that is outside the valid range for the column type. There are a couple of repairs we &lt;EM&gt;could&lt;/EM&gt; do for this:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;delete the entire record&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;insert a dummy value&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P mce_keep="true"&gt;#1 isn't very palatable because then we've lost data and its not a &lt;EM&gt;structural&lt;/EM&gt; problem in the database so doesn't &lt;EM&gt;have&lt;/EM&gt; to be repaired. #2 is dangerous - what value should we choose as the dummy value? Any value we put in may adversely affect business logic, or fire a trigger, or have some unwelcome meaning in the context of the table - even a NULL. Given these problems, we chose to allow people to fix the corrupt values themselves.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Metadata corruption&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Here's an example of this on SQL Server 2005:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;Msg 3854, Level 16, State 1, Line 2&lt;BR&gt;Attribute (referenced_major_id=2089058478) of row (class=0,object_id=2105058535,column_id=0,referenced_major_id=2089058478,referenced_minor_id=0) in sys.sql_dependencies has a matching row (object_id=2089058478) in sys.objects (type=SN) that is invalid.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;This example is relatively benign. There are other examples that will cause CHECKDB to terminate - not as bad as the critical system table corruption example above, but enough that CHECKDB doesn't trust the metadata enough to use it to drive consistency checks. Repairing metadata corruption has the same problems as repairing critical system table corruption - any repair means deleting metadata about one or more tables, and hence deleting the tables themselves. It's far better to leave the corruption unrepaired so that as much data as possible can be extracted from the remaining tables.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Summary&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Repair can't fix everything. You may end up having to perform manual and time-consuming data extraction from the corrupt database and losing lots of data because of, say,&amp;nbsp;a critical system table corruption. Bottom line (as usual) - make sure you have valid backups so you don't get into this state!&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;BR&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1598373" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/On-Disk+Structures/default.aspx">On-Disk Structures</category></item><item><title>CHECKDB (Part 7): How long will CHECKDB take to run?</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2007/01/24/how-long-will-checkdb-take-to-run.aspx</link><pubDate>Wed, 24 Jan 2007 16:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1521725</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/1521725.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=1521725</wfw:commentRss><description>&lt;P&gt;This is a question I see every so often and it cropped up again this morning so I'll use it as the subject for this week's blog post.&lt;/P&gt;
&lt;P&gt;There are several ways I &lt;EM&gt;could&lt;/EM&gt; answer this:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;the&amp;nbsp;unhelpful answer&lt;/STRONG&gt; - I've got no idea.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;the almost-helpful answer&lt;/STRONG&gt; - how long did it take to run last time and are the conditions exactly the same?&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;the answer I usually give&lt;/STRONG&gt; - it depends.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Now, many people would see the third answer as being somewhat equivalent to the first answer - unhelpful. The problem is that there are many factors which influence how long CHECKDB will take to run. Let me explain the ten most important factors so you get an idea why this is actually a helpful answer. These aren't in any particular order of importance.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;1) The size of the database&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Pretty obvious...&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;2) Concurrent IO load on the server&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;At the simplest level, what is CHECKDB going to do? It reads every allocated page in the database. That's a lot of IO. CHECKDB takes great pains to do the most efficient IO it can and read the database pages in their physical order with plenty of readahead so that the disk heads move smoothly across the disks (rather than jumping around randomly and incurring disk head seek delays). If there's no concurrent IO load on the server, then the IOs will be as efficient as CHECKDB can make them. However, introducing any additional IO from SQL Server means that the disk heads will be jumping around - slowing down the CHECKDB IOs. If the IO subsystem is at capacity already from CHECKDB's IO demands, any additional IO is going to reduce the IO bandwidth available to CHECKDB - slowing it down.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;3) Concurrent CPU activity on the server&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;At the next level of simplicity, CHECKDB is going to process every page it reads in some way. Depending on the various options you've specified and the database schema (details below), that's going to use a lot of CPU - it's possible that the server may be pegged at 100% CPU when CHECKDB is running. If there's any additional workload on the server, that's going to take CPU cycles away from CHECKDB and it going to slow it down.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Basically what these first two points are saying is that CHECKDB is &lt;EM&gt;very resource intensive!&lt;STRONG&gt; &lt;/STRONG&gt;&lt;/EM&gt;Its probably one of the most resource intensive things you can ask SQL Server to do and so it's usually a good idea to not run it during peak workload times, as you'll not only cause CHECKDB to take longer to run, you will slowdown the concurrent workload, possibly unacceptably.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;4) Concurrent update activity on the database&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This is relevant for both SQL 2000 and SQL 2005, but for different reasons.&lt;/P&gt;
&lt;P&gt;In SQL 2000, CHECKDB gets its consistent view of the database from transaction log analysis of concurrent DML transactions (see &lt;A class="" href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/09/623789.aspx" target=_blank mce_href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/09/623789.aspx"&gt;CHECKDB (Part 1): How does CHECKDB get a consistent view of the database&lt;/A&gt; for full details). The more concurrent DML there is while CHECKDB is running, the more transaction log will be generated - and so the longer it will take for CHECKDB to analyze that transaction log. It's possible that on a large multi-CPU box with a ton of concurrent DML and CHECKDB limited to a single CPU that this phase of CHECKDB could take several times longer than the reading and processing of the database pages! (I've seen this in real-life several times.)&lt;/P&gt;
&lt;P&gt;In SQL 2005, CHECKDB gets its consistent view of the database from a database snapshot, which is stored on the same disk volumes as the database itself. If there are&amp;nbsp;a lot of changes in the database while CHECKDB is running, the changed pages are pushed to the snapshot so that it remains consistent. As the snapshot is stored on the same disks as the database, every time&amp;nbsp;page is pushed to the snapshot, the disk head has to move, which interrupts the efficient IO described in #2. Also, whenever CHECKDB goes to read a page and it needs to read the page from the snapshot files instead of the database files, that's another disk head move, and another efficient IO interruption. The more concurrent changes to the database, the more interruptions to efficient IO and the slower the CHECKDB runs.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;5) Throughput capabilities of the IO subsystem&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This one's simple. CHECKDB is going to do a boat-load of IOs and it could even end up being IO-bound (meaning that the CPUs are idle periodically waiting for IOs to complete) depending on the options specified and the database schema. This means that the throughput of the IO subsystem is going to have a direct effect on the run-time of CHECKDB. so, if you have a 1TB database and the IO subsystem can only manage 100MB/sec, it's going to take almost 3 hours just to read the database (1TB / 100MB / 3600 secs) and there's nothing you can do to speed that up except upgrade the IO subsystem.&lt;/P&gt;
&lt;P&gt;I've lost count of the number of times I've heard customers complain that CHECKDB (or index rebuilds or other IO-heavy operations) are running sloooowly only to find that the disk queue lengths are enormous and the IO subsystem it entirely unmatched to the server and workload.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;6) The number of CPUs on the box&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This also really encompasses the Edition of SQL Server that's being run. In Enterprise Edition, CHECKDB can run in parallel across all the CPUs in the box (or as many as the query processor decides to parallelize over when the CHECKDB internal queries are compiled). Running in parallel can give a significant performance boost to CHECKDB and lower run times, as long as the database is also spread over multiple files too (so the IOs can be parallelized). There's a nifty algorithm we use that allows us to run in parallel whcih I'll explain in detail in a future post.&lt;/P&gt;
&lt;P&gt;On the other hand, however, the fact that CHECKDB can run in parallel in Enterprise Edition can be bad for some scenarios, and so some DBAs chose to force CHECKDB to be single-threaded. The way to do this is to turn on the documented trace flag 2528.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;7) The speed of the disks where tempdb is placed&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Running CHECKDB against a VLDB uses lots of memory for internal state and for VLDBs the memory requirement usually exceeds the amount of memory available to SQL Server. In this case, the state is spooled out to tempdb and so the performance of tempdb can be a critical factor in CHECKDB performance.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;8) The complexity of the database schema&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This can have a really high impact on the run-time of CHECKDB because it impacts the amount of CPU that CHECKDB requires. For example, the most expensive checks that CHECKDB does are for non-clustered indexes. We need to check that each row in a non-clustered index maps to exactly one row in the heap or clustered index for the table, and that every heap/clustered index row has exactly one matching row in each non-clustered index. Although there's a highly efficient algorithm for doing this, it still takes around 30% of the total CPU that CHECKDB uses!&lt;/P&gt;
&lt;P&gt;There are&amp;nbsp;a bunch of other checks that are only done if the features have been used in the database - e.g. computed column evaluation, links between off-row LOB values, Service Broker, XML indexes, indexed views - so you can see that empirical factors along aren't enough to determine the run-time.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;9) Which options you've specified&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This is almost the same as #7 in that by specifying various options you're limiting what checks CHECKDB actually performs. For instance, using the WITH NOINDEX option will turn off the non-clustered index checks that I described in #7 and using the WITH PHYSICAL_ONLY option will turn off &lt;EM&gt;all&lt;/EM&gt; logical checks, vastly decreasing the run-time of CHECKDB and making it nearly always IO-bound rather than CPU-bound (in fact this is the most common option that DBAs of VLDBs use to make the run-time of CHECKDB manageable).&lt;/P&gt;
&lt;P&gt;One thing to be aware of - if you specify any repair options, CHECKDB &lt;EM&gt;always&lt;/EM&gt; runs single-threaded, even on a multi-proc box.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;10) The number and type of corruptions that exist in the database&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Again, this is similar to #7 and #8. If there are any corruptions present, there may be extra checks triggered to try to figure out more details of the corruptions. For instance, for the non-clustered index checks, the algorithm is tuned very heavily for the case when there are no corruptions present (the overwhelming majority of cases considering the millions of times CHECKDB is run every day around the world). When a non-clustered index corruption is detected, a more in-depth algorithm has to be used to figure out exactly where the corruption is, which involves re-scanning a bunch of data and so taking a bunch more time. There are a few other algorithms like this too.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Summary&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So you can see that there's no simple answer.&lt;/P&gt;
&lt;P&gt;Now, there's only one time when you should be trying to work out how long a CHECKDB is going to take - when you're planning your regular database maintenance (if you find that it's going to take too long, checkout some of the options for splitting up the checks in my previous post on &lt;A class="" href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/10/20/consistency-checking-options-for-a-vldb.aspx" target=_blank mce_href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/10/20/consistency-checking-options-for-a-vldb.aspx"&gt;CHECKDB (Part 6): Consistency checking options for a VLDB&lt;/A&gt;). If you're faced with a corrupt (or suspected corrupt)&amp;nbsp;database and you're only just starting to think about how long a CHECKDB is going to take - you've screwed up. You should at least know how long a CHECKDB &lt;EM&gt;usually&lt;/EM&gt; takes.&lt;/P&gt;
&lt;P&gt;Of course, there's one more &lt;EM&gt;really&lt;/EM&gt; unhelpful answer I could have given - &lt;EM&gt;how long is a piece of string?!? :-)&lt;/EM&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1521725" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category></item><item><title>Fixing damaged pages using page restore or manual inserts</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2007/01/18/fixing-damaged-pages-using-page-restore-or-manual-inserts.aspx</link><pubDate>Thu, 18 Jan 2007 03:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1485889</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/1485889.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=1485889</wfw:commentRss><description>&lt;P&gt;Here's an interesting scenario that cropped up today. You have a database on a RAID array that failed and has zero'd out a page. How can&amp;nbsp;you get the data back?&lt;/P&gt;
&lt;P&gt;There are two ways to do it, depending on the database recovery model and version of SQL Server - single-page restore or manual insert/select - both of which rely on you having a backup of the database. You can use single-page restore if you're on SQL Server 2005 &lt;EM&gt;and&lt;/EM&gt; the database is in Full or Bulk-Logged recovery mode, otherwise you need to use the manual method, and that will only work as long as you know the data being salvaged hasn't changed since the last backup.&lt;/P&gt;
&lt;P&gt;Let's try them both. Here's a script to create a test database and make a backup of it:&lt;/P&gt;&lt;FONT color=#008000 size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;-- Create the database.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;USE&lt;/FONT&gt;&lt;FONT size=2&gt; master&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;CREATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;ALTER&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; RECOVERY &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FULL&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;-- Create a table to play with.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;USE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;CREATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TABLE&lt;/FONT&gt;&lt;FONT size=2&gt; sales &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;salesID &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;IDENTITY&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;customerID &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DEFAULT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;CONVERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INT&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100000 &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;*&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;RAND&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;()),&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;salesDate &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATETIME&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DEFAULT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;GETDATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(),&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;salesAmount &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;MONEY&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;CREATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;CLUSTERED&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INDEX&lt;/FONT&gt;&lt;FONT size=2&gt; salesCI &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON&lt;/FONT&gt;&lt;FONT size=2&gt; sales &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;salesID&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;-- Populate the table&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;NOCOUNT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DECLARE&lt;/FONT&gt;&lt;FONT size=2&gt; @count &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INT&lt;/P&gt;
&lt;P&gt;SELECT&lt;/FONT&gt;&lt;FONT size=2&gt; @count &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; 0&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;WHILE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;@count &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;&amp;lt;&lt;/FONT&gt;&lt;FONT size=2&gt; 5000&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;BEGIN&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; sales &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;salesAmount&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;100 &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;*&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;RAND&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;());&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SELECT&lt;/FONT&gt;&lt;FONT size=2&gt; @count &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; @count &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;+&lt;/FONT&gt;&lt;FONT size=2&gt; 1&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;END&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;-- Take a full backup.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;BACKUP&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest.bak' &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; INIT&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;I'm going to simulate our scenario by shutting down the database and using a hex editor to zero out page 158 of the database. (This translates to byte offset 1294336 of the file being zero'd for 8192 bytes).&lt;/P&gt;
&lt;P mce_keep="true"&gt;Now if I run checkdb, I get the following:&lt;/P&gt;&lt;FONT size=1&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Msg 8909, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Table error: Object ID 0, index ID -1, partition ID 0, alloc unit ID 0 (type Unknown), page ID (1:158) contains an incorrect page ID in its page header. The PageId in the page header = (0:0).&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 1 consistency errors not associated with any single object.&lt;/P&gt;
&lt;P&gt;Msg 8928, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data): Page (1:158) could not be processed. See other errors for details.&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 1 consistency errors in table 'sales' (object ID 2073058421).&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 2 consistency errors in database 'dbccpagetest'.&lt;/P&gt;
&lt;P&gt;repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (dbccpagetest).&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;&lt;/FONT&gt;What does the page look like?&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; TRACEON &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;3604&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; PAGE &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 158&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 3&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;DBCC execution completed. If DBCC printed error messages, contact your system administrator.&lt;/P&gt;
&lt;P&gt;PAGE: (0:0)&lt;/P&gt;
&lt;P&gt;BUFFER:&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;BUF @0x02C0632C&lt;/P&gt;
&lt;P&gt;bpage = 0x04C12000 bhash = 0x00000000 bpageno = (1:158)&lt;/P&gt;
&lt;P&gt;bdbid = 9 breferences = 0 bUse1 = 37241&lt;/P&gt;
&lt;P&gt;bstat = 0xc00009 blog = 0x89898989 bnext = 0x00000000&lt;/P&gt;
&lt;P&gt;PAGE HEADER:&lt;/P&gt;
&lt;P&gt;Page @0x04C12000&lt;/P&gt;
&lt;P&gt;m_pageId = (0:0) m_headerVersion = 0 m_type = 0&lt;/P&gt;
&lt;P&gt;m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x200&lt;/P&gt;
&lt;P&gt;m_objId (AllocUnitId.idObj) = 0 m_indexId (AllocUnitId.idInd) = 0 Metadata: AllocUnitId = 0&lt;/P&gt;
&lt;P&gt;Metadata: PartitionId = 0 Metadata: IndexId = -1 Metadata: ObjectId = 0&lt;/P&gt;
&lt;P&gt;m_prevPage = (0:0) m_nextPage = (0:0) pminlen = 0&lt;/P&gt;
&lt;P&gt;m_slotCnt = 0 m_freeCnt = 0 m_freeData = 0&lt;/P&gt;
&lt;P&gt;m_reservedCnt = 0 m_lsn = (0:0:0) m_xactReserved = 0&lt;/P&gt;
&lt;P&gt;m_xdesId = (0:0) m_ghostRecCnt = 0 m_tornBits = 16777216&lt;/P&gt;
&lt;P&gt;Allocation Status&lt;/P&gt;
&lt;P&gt;GAM (1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED &lt;/P&gt;
&lt;P&gt;PFS (1:1) = 0x60 MIXED_EXT ALLOCATED 0_PCT_FULL DIFF (1:6) = NOT CHANGED&lt;/P&gt;
&lt;P&gt;ML (1:7) = NOT MIN_LOGGED &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Msg 2514, Level 16, State 5, Line 2&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;DBCC PAGE error: Invalid page type - dump style 3 not possible.&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;&lt;/FONT&gt;Note the error at the end of the output - DBCC PAGE can't do an in-depth dump because it doesn't know what page type the page is. Let's try a full page hex dump using dump style 2 instead:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; PAGE &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 158&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 2&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#808080 size=2&gt;&lt;FONT color=#000000&gt;GO&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;PAGE: (0:0)&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&amp;lt;page header etc skipped for brevity&amp;gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;DATA:&lt;/P&gt;
&lt;P&gt;Memory Dump @0x44F3C000&lt;/P&gt;
&lt;P&gt;44F3C000: 00000000 00020000 00000000 00000000 †................ &lt;/P&gt;
&lt;P&gt;44F3C010: 00000000 00000000 00000000 00000000 †................ &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&amp;lt;deleted for brevity&amp;gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;44F3DFE0: 00000000 00000000 00000000 00000000 †................ &lt;/P&gt;
&lt;P&gt;44F3DFF0: 00000000 00000000 00000000 00000000 †................ &lt;/P&gt;
&lt;P&gt;DBCC execution completed. If DBCC printed error messages, contact your system administrator.&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;It really is all zero. First&amp;nbsp;we'll fix it using page restore.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;USE&lt;/FONT&gt;&lt;FONT size=2&gt; master&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest PAGE &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'1:158' &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest.bak'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Processed 1 pages for database 'dbccpagetest', file 'dbccpagetest' on file 1.&lt;/P&gt;
&lt;P&gt;The roll forward start point is now at log sequence number (LSN) 32000000047000001. Additional roll forward past LSN 33000000001700001 is required to complete the restore sequence.&lt;/P&gt;
&lt;P&gt;RESTORE DATABASE ... FILE=&amp;lt;name&amp;gt; successfully processed 1 pages in 0.176 seconds (0.046 MB/sec).&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;Isn't that cool? You can restore up to 1000 single pages from a backup at a time. For VLDBs, this cuts the recovery time WAY down. Now we need to roll forward the log. We don't have any more log backups so we can finish the roll forward by backing up and restoring the tail of the log.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;-- Need to complete roll forward. Backup the log tail...&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;BACKUP&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;LOG&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest_log.bak' &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; INIT&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;-- ... and restore it again.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;LOG&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest_log.bak'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Processed 5 pages for database 'dbccpagetest', file 'dbccpagetest_log' on file 1.&lt;/P&gt;
&lt;P&gt;BACKUP LOG successfully processed 5 pages in 0.146 seconds (0.248 MB/sec).&lt;/P&gt;
&lt;P&gt;Processed 0 pages for database 'dbccpagetest', file 'dbccpagetest' on file 1.&lt;/P&gt;
&lt;P&gt;RESTORE LOG successfully processed 0 pages in 0.004 seconds (0.000 MB/sec).&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;&lt;/FONT&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;And now we should have a clean database:&lt;FONT color=#008000 size=2&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; CHECKDB &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; NO_INFOMSGS&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Command(s) completed successfully.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;Easy. But what if we can't do a page restore? Assuming I've corrupted the database in exactly the same way again, the first thing is to do is make sure we can restore the backup and then see what data range is on that page:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;RESTORE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest_copy &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest.bak' &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;MOVE&lt;/FONT&gt;&lt;FONT size=2&gt; N&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'dbccpagetest'&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO&lt;/FONT&gt;&lt;FONT size=2&gt; N&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest_copy.mdf'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;MOVE&lt;/FONT&gt;&lt;FONT size=2&gt; N&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'dbccpagetest_log'&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO&lt;/FONT&gt;&lt;FONT size=2&gt; N&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest_log.ldf'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLACE&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; PAGE &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;dbccpagetest_copy&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 158&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 3&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Processed 184 pages for database 'dbccpagetest_copy', file 'dbccpagetest' on file 1.&lt;/P&gt;
&lt;P&gt;Processed 2 pages for database 'dbccpagetest_copy', file 'dbccpagetest_log' on file 1.&lt;/P&gt;
&lt;P&gt;RESTORE DATABASE successfully processed 186 pages in 0.361 seconds (4.205 MB/sec).&lt;/P&gt;
&lt;P&gt;PAGE: (1:158)&lt;/P&gt;
&lt;P&gt;BUFFER:&lt;/P&gt;
&lt;P&gt;BUF @0x02BE8D38&lt;/P&gt;
&lt;P&gt;bpage = 0x03FB4000 bhash = 0x00000000 bpageno = (1:158)&lt;/P&gt;
&lt;P&gt;bdbid = 10 breferences = 1 bUse1 = 38283&lt;/P&gt;
&lt;P&gt;bstat = 0xc00009 blog = 0x159a2159 bnext = 0x00000000&lt;/P&gt;
&lt;P&gt;PAGE HEADER:&lt;/P&gt;
&lt;P&gt;Page @0x03FB4000&lt;/P&gt;
&lt;P&gt;m_pageId = (1:158) m_headerVersion = 1 m_type = 1&lt;/P&gt;
&lt;P&gt;m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8200&lt;/P&gt;
&lt;P&gt;m_objId (AllocUnitId.idObj) = 68 m_indexId (AllocUnitId.idInd) = 256 &lt;/P&gt;
&lt;P&gt;Metadata: AllocUnitId = 72057594042384384 &lt;/P&gt;
&lt;P&gt;Metadata: PartitionId = 72057594038386688 Metadata: IndexId = 1&lt;/P&gt;
&lt;P&gt;Metadata: ObjectId = 2073058421 m_prevPage = (1:157) m_nextPage = (1:159)&lt;/P&gt;
&lt;P&gt;pminlen = 28 m_slotCnt = 245 m_freeCnt = 11&lt;/P&gt;
&lt;P&gt;m_freeData = 7691 m_reservedCnt = 0 m_lsn = (24:453:8)&lt;/P&gt;
&lt;P&gt;m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0&lt;/P&gt;
&lt;P&gt;m_tornBits = -1020457745 &lt;/P&gt;
&lt;P&gt;Allocation Status&lt;/P&gt;
&lt;P&gt;GAM (1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED &lt;/P&gt;
&lt;P&gt;PFS (1:1) = 0x60 MIXED_EXT ALLOCATED 0_PCT_FULL DIFF (1:6) = NOT CHANGED&lt;/P&gt;
&lt;P&gt;ML (1:7) = NOT MIN_LOGGED &lt;/P&gt;
&lt;P&gt;Slot 0 Offset 0x60 Length 31&lt;/P&gt;
&lt;P&gt;Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP &lt;/P&gt;
&lt;P&gt;Memory Dump @0x4542C060&lt;/P&gt;
&lt;P&gt;00000000: 10001c00 d5030000 5bd30000 3f771101 †........[...?w.. &lt;/P&gt;
&lt;P&gt;00000010: b9980000 baa10a00 00000000 0500e0††††............... &lt;/P&gt;
&lt;P&gt;UNIQUIFIER = [NULL] &lt;/P&gt;
&lt;P&gt;Slot 0 Column 1 Offset 0x4 Length 4&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;salesID = 981&lt;/STRONG&gt; &lt;/P&gt;
&lt;P&gt;Slot 0 Column 2 Offset 0x8 Length 4&lt;/P&gt;
&lt;P&gt;customerID = 54107 &lt;/P&gt;
&lt;P&gt;Slot 0 Column 3 Offset 0xc Length 8&lt;/P&gt;
&lt;P&gt;salesDate = Jan 17 2007 4:35PM &lt;/P&gt;
&lt;P&gt;Slot 0 Column 4 Offset 0x14 Length 8&lt;/P&gt;
&lt;P&gt;salesAmount = 69.68 &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&amp;lt;deleted for brevity&amp;gt;&lt;/EM&gt;&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Slot 244 Offset 0x1dec Length 31&lt;/P&gt;
&lt;P&gt;Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP &lt;/P&gt;
&lt;P&gt;Memory Dump @0x4542DDEC&lt;/P&gt;
&lt;P&gt;00000000: 10001c00 c9040000 bfa10000 57771101 †............Ww.. &lt;/P&gt;
&lt;P&gt;00000010: b9980000 c6b80500 00000000 0500e0††††............... &lt;/P&gt;
&lt;P&gt;UNIQUIFIER = [NULL] &lt;/P&gt;
&lt;P&gt;Slot 244 Column 1 Offset 0x4 Length 4&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;salesID = 1225&lt;/STRONG&gt; &lt;/P&gt;
&lt;P&gt;Slot 244 Column 2 Offset 0x8 Length 4&lt;/P&gt;
&lt;P&gt;customerID = 41407 &lt;/P&gt;
&lt;P&gt;Slot 244 Column 3 Offset 0xc Length 8&lt;/P&gt;
&lt;P&gt;salesDate = Jan 17 2007 4:35PM &lt;/P&gt;
&lt;P&gt;Slot 244 Column 4 Offset 0x14 Length 8&lt;/P&gt;
&lt;P&gt;salesAmount = 37.50 &lt;/P&gt;
&lt;P&gt;DBCC execution completed. If DBCC printed error messages, contact your system administrator.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So we're looking at salesID range 981 to 1225 inclusive. Before we can copy the rows back to the damaged database, we need to get rid of the corrupt page. Repair should delete the page for us. First I'm going to take another backup though - just in case something goes wrong!&lt;FONT color=#008000 size=2&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;BACKUP&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; dbccpagetest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TO &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DISK&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\dbccpagetest_corrupt.bak' &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; INIT&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;ALTER&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; SINGLE_USER&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; CHECKDB &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; REPAIR_ALLOW_DATA_LOSS&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH&lt;/FONT&gt;&lt;FONT size=2&gt; NO_INFOMSGS&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;ALTER&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; MULTI_USER&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;&lt;FONT size=1&gt;
&lt;P&gt;Processed 184 pages for database 'dbccpagetest', file 'dbccpagetest' on file 1.&lt;/P&gt;
&lt;P&gt;Processed 4 pages for database 'dbccpagetest', file 'dbccpagetest_log' on file 1.&lt;/P&gt;
&lt;P&gt;BACKUP DATABASE successfully processed 188 pages in 0.380 seconds (4.052 MB/sec).&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;Msg 8909, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Table error: Object ID 0, index ID -1, partition ID 0, alloc unit ID 0 (type Unknown), page ID (1:158) contains an incorrect page ID in its page header. The PageId in the page header = (0:0).&lt;/P&gt;
&lt;P&gt;The error has been repaired.&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 1 consistency errors not associated with any single object.&lt;/P&gt;
&lt;P&gt;CHECKDB fixed 0 allocation errors and 1 consistency errors not associated with any single object.&lt;/P&gt;
&lt;P&gt;Repair: The Clustered index successfully rebuilt for the object "dbo.sales" in database "dbccpagetest".&lt;/P&gt;
&lt;P&gt;Repair: The page (1:158) has been deallocated from object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data).&lt;/P&gt;
&lt;P&gt;Msg 8945, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Table error: Object ID 2073058421, index ID 1 will be rebuilt.&lt;/P&gt;
&lt;P&gt;The error has been repaired.&lt;/P&gt;
&lt;P&gt;Msg 8928, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data): Page (1:158) could not be processed. See other errors for details.&lt;/P&gt;
&lt;P&gt;The error has been repaired.&lt;/P&gt;
&lt;P&gt;Msg 8976, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Table error: Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data). Page (1:158) was not seen in the scan although its parent (1:154) and previous (1:157) refer to it. Check any previous errors.&lt;/P&gt;
&lt;P&gt;The error has been repaired.&lt;/P&gt;
&lt;P&gt;Msg 8978, Level 16, State 1, Line 1&lt;/P&gt;
&lt;P&gt;Table error: Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data). Page (1:159) is missing a reference from previous page (1:158). Possible chain linkage problem.&lt;/P&gt;
&lt;P&gt;The error has been repaired.&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 3 consistency errors in table 'sales' (object ID 2073058421).&lt;/P&gt;
&lt;P&gt;CHECKDB fixed 0 allocation errors and 3 consistency errors in table 'sales' (object ID 2073058421).&lt;/P&gt;
&lt;P&gt;CHECKDB found 0 allocation errors and 4 consistency errors in database 'dbccpagetest'.&lt;/P&gt;
&lt;P&gt;CHECKDB fixed 0 allocation errors and 4 consistency errors in database 'dbccpagetest'.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;We should check the row count to see that the count has dropped from the initial 5000 rows we inserted:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;USE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SELECT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;COUNT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(*)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; SALES&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SELECT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;COUNT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(*)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; sales &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WHERE&lt;/FONT&gt;&lt;FONT size=2&gt; salesID &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;&amp;gt;&lt;/FONT&gt;&lt;FONT size=2&gt; 980 &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;AND&lt;/FONT&gt;&lt;FONT size=2&gt; salesID &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;&amp;lt;&lt;/FONT&gt;&lt;FONT size=2&gt; 1226&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;And we're down to 4755 rows, as expected with zero rows in that range.&amp;nbsp;All we need to do now is to copy the missing rows over from the restored copy. Remember, this will only work if you know that the data being salvaged hasn't changed since the backup was taken - otherwise you'll have old and new data mixed in the table which will play havoc with your business. Before we copy the rows, we know we're got an identity column we'd like to preserve so we set IDENTITY_INSERT on which tells the server not to generate new identity values for the inserted rows.&lt;FONT color=#008000 size=2&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;-- Make sure identity values survive.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;IDENTITY_INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; sales &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;-- Insert the missing rows.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;NOCOUNT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;OFF&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; sales &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;salesID&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; customerID&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; salesDate&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; salesAmount&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SELECT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;*&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest_copy&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;dbo&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;sales &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;AS&lt;/FONT&gt;&lt;FONT size=2&gt; R&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WHERE&lt;/FONT&gt;&lt;FONT size=2&gt; R&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;salesID &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;&amp;gt;&lt;/FONT&gt;&lt;FONT size=2&gt; 980 &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;AND&lt;/FONT&gt;&lt;FONT size=2&gt; R&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;salesID &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;&amp;lt;&lt;/FONT&gt;&lt;FONT size=2&gt; 1226&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;-- Restore identity behavior.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;IDENTITY_INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; sales &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;OFF&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;(245 row(s) affected)&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;We copy over 245 rows and checking the row count again says we're back to 5000 rows.&lt;/P&gt;
&lt;P&gt;I want to post a lot more scenarios like this from now on - this may mean the posts are a little less meaty than last year but should happen a lot more often. If there's any particular scenario you'd like to see covered, add a comment and let me know.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;(First post of the year! The diving vacation was excellent - 100 foot visibility, 85F water, and amazing creatures. I managed to get in 28 dives in the 8 diving days I had. Here's&amp;nbsp;a picture of me about 40ft underwater in Indonesia to close.)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;IMG style="WIDTH: 800px; HEIGHT: 534px" height=534 src="http://www.chewie.members.winisp.net/images/underwater.jpg" width=800 mce_src="http://www.chewie.members.winisp.net/images/underwater.jpg"&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1485889" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category></item><item><title>More undocumented fun: DBCC IND, DBCC PAGE, and off-row columns</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/12/13/More-undocumented-fun_3A00_-DBCC-IND_2C00_-DBCC-PAGE_2C00_-and-off_2D00_row-columns.aspx</link><pubDate>Thu, 14 Dec 2006 01:46:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1278602</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>13</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/1278602.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=1278602</wfw:commentRss><description>&lt;P&gt;&lt;EM&gt;(Final blog post of the year for me. Its been a bit of a wild ride the last 6 months - 7 TechEds on 3 continents, 46 blog posts&amp;nbsp;and&amp;nbsp;some major life changes - but now things have calmed down and I should be back to more regular posting in 2007. Tomorrow I fly out to &lt;A class="" href="http://www.wakatobi.com/" mce_href="http://www.wakatobi.com"&gt;Wakatobi&lt;/A&gt; in Indonesia to go diving with my partner until January, which is some long overdue R&amp;amp;R. I'll post a link to some photos in January - she's already been out there for two weeks on a live-aboard and has over 3000 photos... In the meantime, I have all my loose-ends tied up at work so time to squeeze in a post. Thanks for all your comments and emails this year - I hope you all have a great holiday and may your pagers be silent throughout!)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;At TechEd in November, in one of the sessions I did with &lt;A class="" href="http://www.sqlskills.com/blogs/kimberly/" mce_href="http://www.sqlskills.com/blogs/kimberly/"&gt;Kimberly&lt;/A&gt; we demo'd both DBCC IND and DBCC PAGE in the context of following links to columns that have been pushed off-row when the row size exceeds 8060 bytes. The point of the demo is to show that even if an index is perfectly defragmented, the performance of a query that does a range scan may suffer if off-row columns are part of the result set because getting to those off-row columns involves random IOs.&lt;/P&gt;
&lt;P&gt;What I'd like to do in this post is run through the demo we did, and at the same time introduce you to the undocumented DBCC IND command. This is like DBCC PAGE - it's used extensively internally but isn't documented or supported - use at your own risk. You already know about using DBCC PAGE to investigate page contents from my previous posts (&lt;A class="" href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/08/09/692806.aspx" mce_href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/08/09/692806.aspx"&gt;here&lt;/A&gt; and &lt;A class="" href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/10/625659.aspx" mce_href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/10/625659.aspx"&gt;here&lt;/A&gt;) so I'm not going to go into details.&lt;/P&gt;
&lt;P&gt;To start off, we create a table with a schema that can cause rows to be greater than 8060 bytes. In previous versions, creating a schema like this has always been possible, but actually getting rows larger then 8060 was not. Checkout my previous post on &lt;A class="" href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx" mce_href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx"&gt;IAM chains and allocation units in SQL Server 2005&lt;/A&gt;&amp;nbsp;for more details of large rows (and a few other cool new features in 2005). I'll assume that you've got a database called dbccpagetest that you're using.&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;CREATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TABLE&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(c&lt;/FONT&gt;&lt;FONT size=2&gt;1 &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INT&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&amp;nbsp;&lt;/FONT&gt;&lt;FONT size=2&gt;c2 &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VARCHAR&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;8000&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/FONT&gt;&lt;FONT size=2&gt; c3 &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VARCHAR&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;8000&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;));&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;CREATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;CLUSTERED&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INDEX&lt;/FONT&gt;&lt;FONT size=2&gt; row_cl &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;c1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Now we need to populate the table so we have something to look at.&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'a'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'b'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;));&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;2&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'a'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'b'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;));&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;3&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'a'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'b'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;));&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;4&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'a'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'b'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;));&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;5&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'a'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'b'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;));&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;And now the new command - use DBCC IND to find out which page IDs to look at with DBCC PAGE.&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; IND &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'dbccpagetest'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'rowoverflowtest'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;The output is (prettified in Excel):&lt;/P&gt;
&lt;P mce_keep="true"&gt;
&lt;TABLE class="" style="WIDTH: 445pt; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width=594 border=0 x:str&gt;
&lt;COLGROUP&gt;
&lt;COL style="WIDTH: 28pt; mso-width-source: userset; mso-width-alt: 1336" span=2 width=38&gt;
&lt;COL style="WIDTH: 27pt; mso-width-source: userset; mso-width-alt: 1280" width=36&gt;
&lt;COL style="WIDTH: 28pt; mso-width-source: userset; mso-width-alt: 1308" width=37&gt;
&lt;COL style="WIDTH: 54pt; mso-width-source: userset; mso-width-alt: 2560" width=72&gt;
&lt;COL style="WIDTH: 30pt; mso-width-source: userset; mso-width-alt: 1422" width=40&gt;
&lt;COL style="WIDTH: 42pt; mso-width-source: userset; mso-width-alt: 1991" width=56&gt;
&lt;COL style="WIDTH: 98pt; mso-width-source: userset; mso-width-alt: 4664" width=131&gt;
&lt;COL style="WIDTH: 48pt" width=64&gt;
&lt;COL style="WIDTH: 32pt; mso-width-source: userset; mso-width-alt: 1507" width=42&gt;
&lt;COL style="WIDTH: 30pt; mso-width-source: userset; mso-width-alt: 1422" width=40&gt;
&lt;TBODY&gt;
&lt;TR style="HEIGHT: 43.2pt; mso-height-source: userset" height=58&gt;
&lt;TD class=xl24 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 43.2pt; BACKGROUND-COLOR: transparent" width=38 height=58 class="xl24"&gt;PageFID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=38 class="xl25"&gt;PagePID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=36 class="xl25"&gt;IAMFID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=37 class="xl25"&gt;IAMPID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=72 class="xl25"&gt;ObjectID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl25"&gt;IndexID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=56 class="xl25"&gt;PartitionNumber&lt;/TD&gt;
&lt;TD class=xl29 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 98pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=131 class="xl29"&gt;PartitionID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=64 class="xl25"&gt;iam_chain_type&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=42 class="xl25"&gt;PageType&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl25"&gt;IndexLevel&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 26.4pt" height=35&gt;
&lt;TD class=xl26 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: #c1ccd9; HEIGHT: 26.4pt; BACKGROUND-COLOR: transparent" width=38 height=35 class="xl26" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=38 class="xl27" x:num u1:num&gt;156&lt;/TD&gt;
&lt;TD class=xl28 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=36 class="xl28"&gt;NULL&lt;/TD&gt;
&lt;TD class=xl28 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=37 class="xl28"&gt;NULL&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=72 class="xl27" x:num u1:num&gt;133575514&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=40 class="xl27" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=56 class="xl27" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: windowtext; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" class="xl30"&gt;72057594039959552&lt;/TD&gt;
&lt;TD class=xl28 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=64 class="xl28"&gt;In-row data&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=42 class="xl27" x:num u1:num&gt;10&lt;/TD&gt;
&lt;TD class=xl28 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=40 class="xl28"&gt;NULL&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 27pt" height=36&gt;
&lt;TD class=xl31 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 27pt; BACKGROUND-COLOR: transparent" width=38 height=36 class="xl31" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=38 class="xl32" x:num u1:num&gt;155&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=36 class="xl32" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=37 class="xl32" x:num u1:num&gt;156&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=72 class="xl32" x:num u1:num&gt;133575514&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl32" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=56 class="xl32" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl34 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: windowtext; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" class="xl34"&gt;72057594039959552&lt;/TD&gt;
&lt;TD class=xl33 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=64 class="xl33"&gt;In-row data&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=42 class="xl32" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl32" x:num u1:num&gt;0&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;(I've&amp;nbsp;stripped off the 4 trailing&amp;nbsp;columns, NextPageFID, NextPagePID,&amp;nbsp;PrevPageFID, PrevPagePID so it&amp;nbsp;all fits in the window. They're all zero.)&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;The columns mean:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;PageFID - the file ID of the page&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;PagePID - the page number in the file&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;IAMFID - the file ID of the IAM page that maps this page (this will be NULL for IAM pages themselves as they're not self-referential)&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;IAMPID - the page number in the file of the IAM page that maps this page&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;ObjectID - the ID of the object this page is part of&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;IndexID - the ID of the index this page is part of&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;PartitionNumber - the partition number (as defined by the partitioning scheme for the index) of the partition this page is part of&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;PartitionID - the internal ID of the partition this page is part of&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;iam_chain_type - see &lt;A class="" href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx" mce_href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx"&gt;IAM chains and allocation units in SQL Server 2005&lt;/A&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;PageType - the page type. Some common ones are:&lt;/DIV&gt;&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;1 - data page&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;2 - index page&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;3 and 4 - text pages&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;8 - GAM page&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;9 - SGAM page&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;10 - IAM page&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;11 - PFS page&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;IndexLevel - what level the page is at in the index (if at all). Remember that index levels go from 0 at the leaf to N at the root page (except in clustered indexes in SQL Server 2000 and 7.0 - where there's a 0 at the leaf level (data pages) and a 0 at the next level up (first level of index pages))&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;NextPageFID and NextPagePID - the page ID of the next page in the doubly-linked list of pages at this level of the index&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;PrevPageFID and PrevPagePID - the page ID of the previous page in the doubly-linked list of pages at this level of the index&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;So you can see we've got a single page clustered index with an IAM page. Note that the page IDs returned may differ on your server. Let's look at the data page, focusing on the record for c1 = 3.&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; TRACEON &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;3604&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; PAGE &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 155&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 3&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;/FONT&gt;Don't forget that we need to turn on T3604 first to get the output back to the console. The dump for the 3rd row is (remembering that slots are number from zero, so slot 2 is row 3):&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;Slot 2 Offset 0x216 Length 219&lt;/P&gt;
&lt;P&gt;Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS&lt;/P&gt;
&lt;P&gt;Memory Dump @0x44DCC216&lt;/P&gt;
&lt;P&gt;00000000: 30000800 03000000 04000003 00130077 †0..............w &lt;/P&gt;
&lt;P&gt;00000010: 00db0061 61616161 61616161 61616161 †...aaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000020: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000030: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000040: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000050: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000060: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000070: 61616161 61616162 62626262 62626262 †aaaaaaabbbbbbbbb &lt;/P&gt;
&lt;P&gt;00000080: 62626262 62626262 62626262 62626262 †bbbbbbbbbbbbbbbb &lt;/P&gt;
&lt;P&gt;00000090: 62626262 62626262 62626262 62626262 †bbbbbbbbbbbbbbbb &lt;/P&gt;
&lt;P&gt;000000A0: 62626262 62626262 62626262 62626262 †bbbbbbbbbbbbbbbb &lt;/P&gt;
&lt;P&gt;000000B0: 62626262 62626262 62626262 62626262 †bbbbbbbbbbbbbbbb &lt;/P&gt;
&lt;P&gt;000000C0: 62626262 62626262 62626262 62626262 †bbbbbbbbbbbbbbbb &lt;/P&gt;
&lt;P&gt;000000D0: 62626262 62626262 626262†††††††††††††bbbbbbbbbbb &lt;/P&gt;
&lt;P&gt;UNIQUIFIER = [NULL] &lt;/P&gt;
&lt;P&gt;Slot 2 Column 1 Offset 0x4 Length 4&lt;/P&gt;
&lt;P&gt;c1 = 3 &lt;/P&gt;
&lt;P&gt;Slot 2 Column 2 Offset 0x13 Length 100&lt;/P&gt;
&lt;P&gt;c2 = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&lt;/P&gt;
&lt;P&gt;Slot 2 Column 3 Offset 0x77 Length 100&lt;/P&gt;
&lt;P&gt;c3 = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&lt;/P&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;You can see that all the data is stored in-row. Now&amp;nbsp;we update one of the columns so that the row size exceeds 8060 bytes.&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;UPDATE&lt;/FONT&gt;&lt;FONT size=2&gt; rowoverflowtest &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SET&lt;/FONT&gt;&lt;FONT size=2&gt; c3 &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;REPLICATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'c'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 8000&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WHERE&lt;/FONT&gt;&lt;FONT size=2&gt; c1 &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; 3&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;And run DBCC IND again to see if anything changed. The output is:&lt;/P&gt;
&lt;P mce_keep="true"&gt;
&lt;TABLE class="" style="WIDTH: 445pt; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width=594 border=0 x:str&gt;
&lt;COLGROUP&gt;
&lt;COL style="WIDTH: 28pt; mso-width-source: userset; mso-width-alt: 1336" span=2 width=38&gt;
&lt;COL style="WIDTH: 27pt; mso-width-source: userset; mso-width-alt: 1280" width=36&gt;
&lt;COL style="WIDTH: 28pt; mso-width-source: userset; mso-width-alt: 1308" width=37&gt;
&lt;COL style="WIDTH: 54pt; mso-width-source: userset; mso-width-alt: 2560" width=72&gt;
&lt;COL style="WIDTH: 30pt; mso-width-source: userset; mso-width-alt: 1422" width=40&gt;
&lt;COL style="WIDTH: 42pt; mso-width-source: userset; mso-width-alt: 1991" width=56&gt;
&lt;COL style="WIDTH: 98pt; mso-width-source: userset; mso-width-alt: 4664" width=131&gt;
&lt;COL style="WIDTH: 48pt" width=64&gt;
&lt;COL style="WIDTH: 32pt; mso-width-source: userset; mso-width-alt: 1507" width=42&gt;
&lt;COL style="WIDTH: 30pt; mso-width-source: userset; mso-width-alt: 1422" width=40&gt;
&lt;TBODY&gt;
&lt;TR style="HEIGHT: 43.2pt; mso-height-source: userset" height=58&gt;
&lt;TD class=xl24 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 43.2pt; BACKGROUND-COLOR: transparent" width=38 height=58 class="xl24"&gt;PageFID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=38 class="xl25"&gt;PagePID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=36 class="xl25"&gt;IAMFID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=37 class="xl25"&gt;IAMPID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=72 class="xl25"&gt;ObjectID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl25"&gt;IndexID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=56 class="xl25"&gt;PartitionNumber&lt;/TD&gt;
&lt;TD class=xl32 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 98pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=131 class="xl32"&gt;PartitionID&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=64 class="xl25"&gt;iam_chain_type&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=42 class="xl25"&gt;PageType&lt;/TD&gt;
&lt;TD class=xl25 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 1pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl25"&gt;IndexLevel&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 26.4pt" height=35&gt;
&lt;TD class=xl35 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: windowtext 0.5pt solid; HEIGHT: 26.4pt; BACKGROUND-COLOR: transparent" width=38 height=35 class="xl35" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl36 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=38 class="xl36" x:num u1:num&gt;156&lt;/TD&gt;
&lt;TD class=xl37 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=36 class="xl37"&gt;NULL&lt;/TD&gt;
&lt;TD class=xl37 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=37 class="xl37"&gt;NULL&lt;/TD&gt;
&lt;TD class=xl36 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=72 class="xl36" x:num u1:num&gt;133575514&lt;/TD&gt;
&lt;TD class=xl36 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl36" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl36 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=56 class="xl36" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl38 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 98pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=131 class="xl38"&gt;72057594039959552&lt;/TD&gt;
&lt;TD class=xl37 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=64 class="xl37"&gt;In-row data&lt;/TD&gt;
&lt;TD class=xl36 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=42 class="xl36" x:num u1:num&gt;10&lt;/TD&gt;
&lt;TD class=xl37 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl37"&gt;NULL&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 26.4pt" height=35&gt;
&lt;TD class=xl26 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: #c1ccd9; HEIGHT: 26.4pt; BACKGROUND-COLOR: transparent" width=38 height=35 class="xl26" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=38 class="xl27" x:num u1:num&gt;155&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=36 class="xl27" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=37 class="xl27" x:num u1:num&gt;156&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=72 class="xl27" x:num u1:num&gt;133575514&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=40 class="xl27" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=56 class="xl27" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl33 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 98pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=131 class="xl33"&gt;72057594039959552&lt;/TD&gt;
&lt;TD class=xl28 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=64 class="xl28"&gt;In-row data&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=42 class="xl27" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl27 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: #c1ccd9; BACKGROUND-COLOR: transparent" width=40 class="xl27" x:num u1:num&gt;0&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 39.6pt" height=53&gt;
&lt;TD class=xl39 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: windowtext 0.5pt solid; HEIGHT: 39.6pt; BACKGROUND-COLOR: transparent" width=38 height=53 class="xl39" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl40 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=38 class="xl40" x:num u1:num&gt;158&lt;/TD&gt;
&lt;TD class=xl41 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=36 class="xl41"&gt;NULL&lt;/TD&gt;
&lt;TD class=xl41 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=37 class="xl41"&gt;NULL&lt;/TD&gt;
&lt;TD class=xl40 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=72 class="xl40" x:num u1:num&gt;133575514&lt;/TD&gt;
&lt;TD class=xl40 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl40" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl40 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=56 class="xl40" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl42 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 98pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=131 class="xl42"&gt;72057594039959552&lt;/TD&gt;
&lt;TD class=xl41 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=64 class="xl41"&gt;Row-overflow data&lt;/TD&gt;
&lt;TD class=xl40 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=42 class="xl40" x:num u1:num&gt;10&lt;/TD&gt;
&lt;TD class=xl41 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: windowtext 0.5pt solid; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 0.5pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl41"&gt;NULL&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 40.2pt" height=54&gt;
&lt;TD class=xl29 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: windowtext 1pt solid; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 40.2pt; BACKGROUND-COLOR: transparent" width=38 height=54 class="xl29" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=38 class="xl30" x:num u1:num&gt;157&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 27pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=36 class="xl30" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 28pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=37 class="xl30" x:num u1:num&gt;158&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 54pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=72 class="xl30" x:num u1:num&gt;133575514&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl30" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 42pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=56 class="xl30" x:num u1:num&gt;1&lt;/TD&gt;
&lt;TD class=xl34 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: windowtext; WIDTH: 98pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=131 class="xl34"&gt;72057594039959552&lt;/TD&gt;
&lt;TD class=xl31 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 48pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=64 class="xl31"&gt;Row-overflow data&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 32pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=42 class="xl30" x:num u1:num&gt;3&lt;/TD&gt;
&lt;TD class=xl30 style="BORDER-RIGHT: windowtext 1pt solid; BORDER-TOP: #c1ccd9; BORDER-LEFT: #c1ccd9; WIDTH: 30pt; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" width=40 class="xl30" x:num u1:num&gt;0&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;(Again, I've stripped off the trailing 4 columns - they're all zero)&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Cool - we have another IAM page and a text page, in a row-overflow IAM chain. So something must have been pushed off-row into page (1:157). Let's have another look at the clustered-index data page, focusing on the 3rd row again:&lt;FONT size=1&gt;&lt;/P&gt;
&lt;P&gt;Slot 2 Offset 0x4a7 Length 143&lt;/P&gt;
&lt;P&gt;Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS&lt;/P&gt;
&lt;P&gt;Memory Dump @0x44DCC4A7&lt;/P&gt;
&lt;P&gt;00000000: 30000800 03000000 04000003 00130077 †0..............w &lt;/P&gt;
&lt;P&gt;00000010: 008f8061 61616161 61616161 61616161 †...aaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000020: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000030: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000040: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000050: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000060: 61616161 61616161 61616161 61616161 †aaaaaaaaaaaaaaaa &lt;/P&gt;
&lt;P&gt;00000070: 61616161 61616102 00004401 000000a6 †aaaaaaa...D..... &lt;/P&gt;
&lt;P&gt;00000080: 2e000040 1f00009d 00000001 000000††††...@........... &lt;/P&gt;
&lt;P&gt;UNIQUIFIER = [NULL] &lt;/P&gt;
&lt;P&gt;Slot 2 Column 1 Offset 0x4 Length 4&lt;/P&gt;
&lt;P&gt;c1 = 3 &lt;/P&gt;
&lt;P&gt;Slot 2 Column 2 Offset 0x13 Length 100&lt;/P&gt;
&lt;P&gt;c2 = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&lt;/P&gt;
&lt;P&gt;c3 = [BLOB Inline Root] Slot 2 Column 3 Offset 0x77 Length 24&lt;/P&gt;
&lt;P&gt;Level = 0 Unused = 68 UpdateSeq = 1&lt;/P&gt;
&lt;P&gt;TimeStamp = 782630912 &lt;/P&gt;
&lt;P&gt;Link 0&lt;/P&gt;
&lt;P&gt;Size = 8000 RowId = (1:157:0) &lt;/P&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;The 2nd varchar column is no longer stored on the page - instead the value have been replaced with an in-row blob root, pointing to an 8000 byte long blob fragment stored in slot 0 of page (1:157). If we dump it with DBCC PAGE we should see its got our value in:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;DBCC&lt;/FONT&gt;&lt;FONT size=2&gt; PAGE &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;dbccpagetest&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 1&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 157&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 3&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;And the output is (slightly curtailed):&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;PAGE: (1:157)&lt;/P&gt;
&lt;P&gt;BUFFER:&lt;/P&gt;
&lt;P&gt;BUF @0x02BE8D84&lt;/P&gt;
&lt;P&gt;bpage = 0x03FB6000 bhash = 0x00000000 bpageno = (1:157)&lt;/P&gt;
&lt;P&gt;bdbid = 9 breferences = 0 bUse1 = 8105&lt;/P&gt;
&lt;P&gt;bstat = 0xc0010b blog = 0x1432159b bnext = 0x00000000&lt;/P&gt;
&lt;P&gt;PAGE HEADER:&lt;/P&gt;
&lt;P&gt;Page @0x03FB6000&lt;/P&gt;
&lt;P&gt;m_pageId = (1:157) m_headerVersion = 1 m_type = 3&lt;/P&gt;
&lt;P&gt;m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x8000&lt;/P&gt;
&lt;P&gt;m_objId (AllocUnitId.idObj) = 117 m_indexId (AllocUnitId.idInd) = 256 &lt;/P&gt;
&lt;P&gt;Metadata: AllocUnitId = 72057594045595648 &lt;/P&gt;
&lt;P&gt;Metadata: PartitionId = 72057594039959552 Metadata: IndexId = 1&lt;/P&gt;
&lt;P&gt;Metadata: ObjectId = 133575514 m_prevPage = (0:0) m_nextPage = (0:0)&lt;/P&gt;
&lt;P&gt;pminlen = 0 m_slotCnt = 1 m_freeCnt = 80&lt;/P&gt;
&lt;P&gt;m_freeData = 8110 m_reservedCnt = 0 m_lsn = (21:107:19)&lt;/P&gt;
&lt;P&gt;m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0&lt;/P&gt;
&lt;P&gt;m_tornBits = 0 &lt;/P&gt;
&lt;P&gt;Allocation Status&lt;/P&gt;
&lt;P&gt;GAM (1:2) = ALLOCATED SGAM (1:3) = ALLOCATED &lt;/P&gt;
&lt;P&gt;PFS (1:1) = 0x64 MIXED_EXT ALLOCATED 100_PCT_FULL DIFF (1:6) = CHANGED&lt;/P&gt;
&lt;P&gt;ML (1:7) = NOT MIN_LOGGED &lt;/P&gt;
&lt;P&gt;Blob row at: Page (1:157) Slot 0 Length: 8014 Type: 3 (DATA)&lt;/P&gt;
&lt;P&gt;Blob Id:782630912&lt;/P&gt;
&lt;P&gt;44DCC06E: 63636363 63636363 63636363 63636363 cccccccccccccccc&lt;/P&gt;
&lt;P&gt;44DCC07E: 63636363 63636363 63636363 63636363 cccccccccccccccc&lt;/P&gt;
&lt;P&gt;44DCC08E: 63636363 63636363 63636363 63636363 cccccccccccccccc&lt;/P&gt;
&lt;P&gt;&amp;lt;snipped out for brevity&amp;gt;&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;44DCDF7E: 63636363 63636363 63636363 63636363 cccccccccccccccc&lt;/P&gt;
&lt;P&gt;44DCDF8E: 63636363 63636363 63636363 63636363 cccccccccccccccc&lt;/P&gt;
&lt;P&gt;44DCDF9E: 63636363 63636363 63636363 63636363 cccccccccccccccc&lt;/P&gt;
&lt;P&gt;DBCC execution completed. If DBCC printed error messages, contact your system administrator.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;Yep - that's our updated column.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Now, this is a contrived example to force columns off-row, but you can imagine a case where a column is unexpectedly pushed off-row in some rows of a table and suddenly a query slows down. You look at the fragmentation and the query plan and everything looks good but don't realize that you're taking random IOs to return the columns you've asked for.&lt;/P&gt;
&lt;P mce_keep="true"&gt;That's all - now it's time for me to go and pack my diving gear and head off towards the sun (20 1/2 hours of flights over 31 1/2 hours to get to Bali tomorrow - ugh!). Have fun playing with DBCC over the holidays and I'll be back in January.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1278602" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Index+Fragmentation+Series/default.aspx">Index Fragmentation Series</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/On-Disk+Structures/default.aspx">On-Disk Structures</category></item><item><title>CHECKDB (Part 6): Consistency checking options for a VLDB</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/10/20/consistency-checking-options-for-a-vldb.aspx</link><pubDate>Fri, 20 Oct 2006 05:57:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:852006</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/852006.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=852006</wfw:commentRss><description>&lt;P&gt;&lt;EM&gt;(Yippee - just finished my certification dives and got my PADI Open Water certification - just in time for our dive trip to Indonesia in December :-)&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This is a question that comes up a lot - in fact 3 times this week already - most recently during a guest lecture I did on DBCC for one of Kimberly's popular "&lt;A class="" href="http://www.sqlskills.com/default.asp" mce_href="http://www.sqlskills.com/default.asp"&gt;Immersion Events&lt;/A&gt;". The question is: &lt;EM&gt;how can I run consistency checks on a VLDB?&lt;/EM&gt; &lt;/P&gt;
&lt;P&gt;We're talking hundreds of&amp;nbsp;GBs or&amp;nbsp;1 TB or more. These databases are&amp;nbsp;now common on SQL Server 2000 and 2005, with more migrations happening all the time.&amp;nbsp;Any sensible DBA knows the value of running consistency checks, even when the system is behaving perfectly and the hardware is rock-solid. The two problems that people have with running a full DBCC CHECKDB on their VLDB are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;It takes a long time to run (proportional to the database size and schema complexity).&lt;/LI&gt;
&lt;LI&gt;It uses lots of resources.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;So it uses lots of resources for a long time.&amp;nbsp;Even with a decent sized maintenance window, the CHECKDB may well run over into normal operations.&amp;nbsp;There's also the case of a system that's&amp;nbsp;already pegged in more or more resource dimensions (memory, CPU, IO bandwidth).&amp;nbsp;Whatever the case, there are a number of options:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Don't run consistency checks&lt;/LI&gt;
&lt;LI&gt;Run a DBCC CHECKDB using the WITH PHYSICAL_ONLY option&lt;/LI&gt;
&lt;LI&gt;Use SQL Server 2005's partitioning feature and devise a consistency checking plan around that&lt;/LI&gt;
&lt;LI&gt;Figure out your own scheme to divide up the consistency checking work over several days&lt;/LI&gt;
&lt;LI&gt;Use a separate system&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Let's look at each in turn.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Don't run consistency checks&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Don't be daft. Don't even think about using this option. If you absolutely&amp;nbsp;cannot figure out a way to get consistency checks on your system, send me email and I'll help you. Now let's move on to serious options...&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Use WITH PHYSICAL_ONLY&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;A full CHECKDB does a lot of stuff - see my &lt;A class="" href="https://blogs.msdn.com/sqlserverstorageengine/archive/tags/CHECKDB+Series/default.aspx" mce_href="https://blogs.msdn.com/sqlserverstorageengine/archive/tags/CHECKDB+Series/default.aspx"&gt;CHECKDB internals series&lt;/A&gt; for more details. You can vastly reduce the run-time and resource-usage of CHECKDB by using the WITH PHYSICAL_ONLY option. With this option, CHECKDB will&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Run the equivalent of&amp;nbsp;DBCC CHECKALLOC (i.e. check all the allocation structures)&lt;/LI&gt;
&lt;LI&gt;Read and audit every allocated page in the database&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;So it skips all the logical checks, inter-page checks, and things like DBCC CHECKCATALOG. The fact that all allocated pages are read means that:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Any pages that cannot be read at all (i.e. 823 errors) will be discovered&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;If&amp;nbsp;page checksums are enabled in SQL Server 2005, any corruptions caused by storage hardware will be discovered (as the page checksum will have changed).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;So there's a trade-off of consistency checking depth against runtime and resource usage.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Use the partitioning feature to your advantage&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;One of the obvious ways to reduce the time/resources issue is to partition the load. If you're using the partitioning feature in SQL Server 2005 then you're already setup for this. Given that you've hopefully got your partitions stored on seperate filegroups, you can use the DBCC CHECKFILEGROUP command.&lt;/P&gt;
&lt;P&gt;Consider this example -&amp;nbsp;you have the database partitioned by date such that the current month is on a read-write filegroup and the past 11 months are on read-only filegroups (data from more than a year ago is on some offline storage medium). The prior months also have multiple backups on various media so are considered much 'safer' than the current month. It makes sense then that you don't need to check these filegroups as often as the current month's filegroup so an example consistency checking scheme would be:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Run a DBCC CHECKFILEGROUP on each read-only filegroup every week or two&lt;/LI&gt;
&lt;LI&gt;Run a DBCC CHECKFILEGROUP on the read-write filegroup every day or two (depending on the stability of the hardware, the criticality of the data, and the frequency and comprehensiveness of your backup strategy).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;I know of several companies who've made the decision to move to SQL Server 2005 in part because of this capability to easily divide up the consistency checking.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Figure out your own way to partition the checks&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;If you're on SQL Server 2000, or you just haven't partitioned your database, then there are ways you can split up the consistency checking workload so that it fits within a maintenance window. Here's one scheme that I've recommended to several customers:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Run a bi-weekly DBCC CHECKALLOC&lt;/LI&gt;
&lt;LI&gt;Figure out your largest tables (by number of pages) and split the total number into 7 buckets, such that there are a roughly equal number of database pages in each bucket.&lt;/LI&gt;
&lt;LI&gt;Take all the remaining tables in the database and divide them equally between the 7 buckets (using number of pages again)&lt;/LI&gt;
&lt;LI&gt;On Sunday:&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;Run a DBCC CHECKALLOC&lt;/LI&gt;
&lt;LI&gt;Run a DBCC CHECKCATALOG&lt;/LI&gt;
&lt;LI&gt;Run a DBCC CHECKTABLE on each table in the first bucket&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;On Monday, Tuesday, Wednesday:&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;Run a DBCC CHECKTABLE on each table in the 2nd, 3rd, 4th buckets, respectively&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;On Thursday:&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;Run a DBCC CHECKALLOC&lt;/LI&gt;
&lt;LI&gt;Run a DBCC CHECKTABLE on each table in the 5th bucket&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;On Friday and Saturday:&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;Run a DBCC CHECKTABLE on each table in the 6th and 7th buckets, respectively&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;P&gt;In pre-RTM builds of SQL Server 2005, DBCC CHECKTABLE could not bind to the critical system tables, just like with T-SQL - but that's fixed so you can cover all system tables in SQL Server 2000 and 2005 using the method above. Here's what I mean:&lt;/P&gt;
&lt;P&gt;C:\Documents and Settings\prandal&amp;gt;osql /E&lt;BR&gt;1&amp;gt; select * from sys.sysallocunits&lt;BR&gt;2&amp;gt; go&lt;BR&gt;Msg 208, Level 16, State 1, Server SUNART, Line 1&lt;BR&gt;Invalid object name 'sys.sysallocunits'.&lt;BR&gt;1&amp;gt; dbcc checktable ('sys.sysallocunits')&lt;BR&gt;2&amp;gt; go&lt;BR&gt;DBCC results for 'sysallocunits'.&lt;BR&gt;There are 112 rows in 2 pages for object "sysallocunits".&lt;BR&gt;DBCC execution completed. If DBCC printed error messages, contact your system&lt;BR&gt;administrator.&lt;BR&gt;1&amp;gt;&lt;/P&gt;
&lt;P&gt;There's one drawback to this method -&amp;nbsp;a new internal database snapshot is created each time you start a new DBCC command, even for a DBCC CHECKTABLE. If the update workload on the database is significant, then there could be a lot of transaction log to recover each time the database snapshot is created - leading to a long total run-time. In this case, you may need to alter the number of buckets you use to make the total operation fit within your available window.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Use a separate system&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;This alternative is relatively simple - restore your backup (you are taking regular backups, right?) on another system and run a full CHECKDB on the restored database. This offloads the consistency checking burden from the production system and also allows you to check that your backups are valid (which&amp;nbsp;you're already checking though, right?). There are some drawbacks to this however:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;You need to have sufficient disk space on the spare system to be able to restore the backup onto. If the production database is several TB, you need the same several TB on the spare box. This equates to a non-trivial amount of money - initial capital investment plus ongoing storage mgmt costs. (I'm working on this though - I have a patent on consistency checking a database in a backup without restoring it - unclear at this time whether it will make it into Katmai.)&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;If the consistency checks find an error, you don't know for sure that the database is corrupt on the production system. It could be a problem with the spare box that's caused the corruption. The only way to know for sure is to run a consistency check on the production system. This is a small price to pay though, because most of the time the consistency checks on the spare system will be ok, so you know the production database was clean at the time the backup was taken.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Summary&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;You've got a bunch of choices to allow you to run consistency checks, so there's really no excuse for not knowing (within a reasonable timeframe) that something's gone wrong with your database. If you need further help working out what to do, or just want a critical eye cast over the plan you've come up with, send me an email at &lt;A href="mailto:prandal@microsoft.com"&gt;prandal@microsoft.com&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;(One of the other questions that also keeps coming up is: &lt;EM&gt;when are you going to write the whitepaper you promised?&lt;/EM&gt; Q1CY07 - honestly!)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=852006" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category></item><item><title>CHECKDB (Part 5): What does CHECKDB really do? (part 4 of 4)</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/09/20/763447.aspx</link><pubDate>Wed, 20 Sep 2006 12:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:763447</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/763447.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=763447</wfw:commentRss><description>&lt;P&gt;&lt;EM&gt;(Another airport, another blog post - I really must make an effort to come up with more &lt;/EM&gt;&lt;EM&gt;original banter - I'm sure I've used that line before. TechEd Guangzhou has finished and I'm on the &lt;/EM&gt;&lt;EM&gt;way to Beijing for TechEd #3. Checking in and getting through security were challenging to say the &lt;/EM&gt;&lt;EM&gt;least this morning - there seemed to be problems at every turn, exacerbated by my China Southern &lt;/EM&gt;&lt;EM&gt;airlines chaperone who spoke limited English (or what I should really say is that the problem was I &lt;/EM&gt;&lt;EM&gt;don't speak Mandarin). Finally at the security checkpoint they asked for my ticket as well as my &lt;/EM&gt;&lt;EM&gt;boarding pass - try explaining "e-ticket" to someone who doesn't speak the same language...)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;So part 4 of the high-level explanation of what &lt;FONT face="Courier New"&gt;DBCC CHECKDB&lt;/FONT&gt; does will focus on the three completely new sets of checks that are in CHECKDB in SQL Server 2005. Well, the metadata checks (i.e. &lt;FONT face="Courier New"&gt;DBCC CHECKCATALOG&lt;/FONT&gt;) used to exist but so many people used to run both CHECKDB and &lt;FONT face="Courier New"&gt;DBCC CHECKCATALOG&lt;/FONT&gt; that I thought I'd make it easier in SQL Server 2005 by running &lt;FONT face="Courier New"&gt;DBCC CHECKCATALOG&lt;/FONT&gt; as part of CHECKDB. Maybe in Katmai we'll add in &lt;FONT face="Courier New"&gt;DBCC CHECKCONSTRAINTS&lt;/FONT&gt; - haven't decided yet.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Primitive checks of critical system tables&lt;/STRONG&gt;&lt;BR&gt;(Part 1...)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Allocation checks&lt;/STRONG&gt;&lt;BR&gt;(Part2...)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Logical checks of critical system tables&lt;/STRONG&gt;&lt;BR&gt;&lt;STRONG&gt;Logical checks of all tables&lt;/STRONG&gt;&lt;BR&gt;(Part 3...)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Service Broker checks&lt;/STRONG&gt;&lt;BR&gt;&lt;STRONG&gt;Metadata cross-checks&lt;/STRONG&gt;&lt;BR&gt;&lt;STRONG&gt;Indexed view and XML index checks&lt;/STRONG&gt;&lt;BR&gt;Its important that these checks are done after the per-table logical checks. This is because any repairs done as part of the per-table checks may affect the outcome of these checks quite substantially.&lt;/P&gt;
&lt;P&gt;Let's look at an example of this. Imagine the case where an indexed view is based on a join between two tables, &lt;FONT face="Courier New"&gt;foo&lt;/FONT&gt; and &lt;FONT face="Courier New"&gt;bar&lt;/FONT&gt;. Table &lt;FONT face="Courier New"&gt;foo&lt;/FONT&gt; has a damaged page and is damaged in a way that reading the page as part of a query would not recognize - because full page audits are not done as part of regular page reads. The damage is such that the page has to be deleted as part of repair - thereby changing the results of the view. If the indexed view was checked &lt;EM&gt;before&lt;/EM&gt; tables &lt;FONT face="Courier New"&gt;foo&lt;/FONT&gt; and &lt;FONT face="Courier New"&gt;bar&lt;/FONT&gt;, then the repair that was done would not get reflected in the indexed view and so the indexed view would essentially be corrupt. The same logic holds for checking XML indexes and Service Broker tables.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;(Ok - in the air now with some serious turbulence - luckily I popped a Dramamine before we took off. And, more jellyfish in the in-flight meal - very cool :-) The 1st class cabin has what looks like a fully stocked bar - a little too early at 10am to be starting, although it could make for some interesting blog posts...)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Service Broker checks&lt;/STRONG&gt;&lt;BR&gt;The Service Broker dev team wrote a comprehensive set of checks of the data stored in their internal on-disk structures. The checks validate the relationships between conversations, endpoints, messages and queues. For example:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;a conversation must have two endpoints 
&lt;LI&gt;a service must be related to a valid contract 
&lt;LI&gt;a service must be related to a valid queue 
&lt;LI&gt;a message must have a valid message type&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;What's even cooler is that they implemented a set of logical repairs, so if one of their internal tables was damaged, and repaired by the earlier logical checks, then the Service Broker repair code can clean up any Service Broker entities and entity relationships that were damaged too.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Metadata cross-checks&lt;/STRONG&gt;&lt;BR&gt;The Metadata team also wrote a great set of checks for the relational metadata stored in the system tables. These checks that are run here are the same code that's run for &lt;FONT face="Courier New"&gt;DBCC CHECKCATALOG&lt;/FONT&gt;. The actual checks themselves in SQL Server 2005 are far more involved than in SQL Server 2000, and they're done way more efficiently too. However, they're not comprehensive by any means - we'll add some more checks during Katmai.&lt;/P&gt;
&lt;P&gt;The checks only cover the &lt;EM&gt;relational&lt;/EM&gt; metadata - i.e. the relationships between system table storing relational metadata. There are no such checks for the tables storing the storage engine metadata (also known as the &lt;EM&gt;critical system tables&lt;/EM&gt; that were described in &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/19/636410.aspx"&gt;Part 1&lt;/A&gt;&amp;nbsp;of this 4 part sub-series. At present, these relationships between these tables are checked implicitly by the metadata checks I described in the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/09/18/761287.aspx"&gt;last post&lt;/A&gt;. The checks are a series of validations between the various system tables, such as checking each rowset referenced in the &lt;FONT face="Courier New"&gt;sysrowsetcolumns&lt;/FONT&gt; system table exists in the &lt;FONT face="Courier New"&gt;sysrowsets&lt;/FONT&gt; system table.&lt;/P&gt;
&lt;P&gt;There are no repairs for metadata corruptions. Metadata corruptions are extremely difficult to deal with because changing/deleting metadata has an effect on the entire table the corrupt metadata describes and could potentially be as bad as deleting the table - a table without metadata is just a collection of pages with indecipherable rows (well, not quite true - its &lt;EM&gt;possible&lt;/EM&gt; to decipher any record without metadata but it requires human intervention and is incredibly hard).&lt;/P&gt;
&lt;P&gt;Its possible we may put in some limited metadata repairs in a future release, but the frequency of their occurence in the field is so low that I decided that the engineering investment was not justified for SQL Server 2005 and so didn't push it. So - if you get any metadata corruption, you need to restore from your backups which, of course, after reading through my blog, you've been scared into making sure you have, right?...&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Indexed view and XML index checks&lt;/STRONG&gt;&lt;BR&gt;These are very cool and many thanks to &lt;EM&gt;Conor Cunningham&lt;/EM&gt; (dev lead of one of the two Query Optimizer teams) for helping work out how to do this.The indexed view contains the persisted results of a query, and we have the actual query it persists stored in metadata - so the easiest way to check whether the indexed view is accurate is to recalculate the view results into a temp table in TEMPDB and then compare the calculated values with the values persisted in the indexed view. The view is regenerated into a temporary table and then two concurrent left-anti-semi-joins are run, that basically return all the rows in the indexed view that are not in the recalculated view results, and vice-versa. This gives us all the rows that are extraneous in the indexed view and all the rows that are missing from it.&lt;/P&gt;
&lt;P&gt;Indexed-view problems can also be repaired. The repair for extra rows is to delete them one by one (using internal query syntax that only works from DBCC), and the repair for missing rows is to rebuild the indexed view. This is done by simply disabling the indexed view and then bringing it back online (which rebuilds it).&lt;/P&gt;
&lt;P&gt;There are two drawbacks to the indexed view checks if the views are large:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;it can take up a lot of space in tempdb 
&lt;LI&gt;it can take a lot of time to run the regeneration of the indexed views and to run the left-anti-semi-joins&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;So if you upgraded your database from SQL Server 2000 and you regularly run full CHECKDBs (i.e. without using &lt;FONT face="Courier New"&gt;WITH PHYSICAL_ONLY&lt;/FONT&gt;), then you may see a run-time increase for CHECKDB on SQL Server 2005 - this is documented in BOL and the README.&lt;/P&gt;
&lt;P&gt;XML index checks work in a similar way. The XML blobs in the table are re-shredded and checked against the shredding that's persisted in the primary XML index. If anything is wrong, the primary XML index is recreated.&lt;/P&gt;
&lt;P&gt;And that's it. Now you have a complete picture of what's going on with CHECKDB when it runs. In the next few posts I want to give some insight into how CHECKDB manages to do all these checks while only making a single pass through the database and shed some light on how repair works. Until then - time to chill out before doing more sessions in Beijing tomorrow... &lt;EM&gt;qing lai yiping pijiu&lt;/EM&gt;!!!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=763447" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category></item><item><title>CHECKDB (Part 4): What does CHECKDB really do? (part 3 of 4)</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/09/18/761287.aspx</link><pubDate>Tue, 19 Sep 2006 00:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:761287</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/761287.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=761287</wfw:commentRss><description>&lt;DIV&gt;&lt;EM&gt;(OK - I was wrong about the posting frequency - events overtook me and I got bogged down preparing for these TechEds. China is an amazing place and I wish I had more time to soak up some of its culture while I'm here but with the TechEds being so close together there's little time for anything except sessions, email, taxis, flying, sleeping, jellyfish... I did manage to go to the 400 year old Yuyuan Gardens in Shanghai, which are well worth a visit. Now I'm sitting here next to the Pearl River in Guangzhou waiting to do DAT305: Choosing a High Availability Solution -&amp;nbsp;so time to squeeze in another post.)&lt;/EM&gt;&lt;/DIV&gt;
&lt;DIV&gt;
&lt;P&gt;In the&amp;nbsp;previous posts of this series, I covered the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/19/636410.aspx"&gt;system table checks&lt;/A&gt;&amp;nbsp;that have to be done before anything else can be checked by CHECKDB, and the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/07/18/670341.aspx"&gt;allocation checks&lt;/A&gt;&amp;nbsp;that have to be done before any of the logical checks. Now I want to cover the meat of the functionality in CHECKDB -&amp;nbsp;the logical checks. Note - this is a description of what happens for SQL Server 2005 - its pretty similar in SQL Server 2000.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Primitive checks of critical system tables&lt;/STRONG&gt;&lt;BR&gt;(Part 1...)&lt;/P&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;STRONG&gt;Allocation checks&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;(Part 2...)&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;&lt;STRONG&gt;Logical checks of critical system tables&lt;/STRONG&gt;&lt;BR&gt;&lt;STRONG&gt;Logical checks of all tables&lt;BR&gt;&lt;/STRONG&gt;Although this section has two titles, the actual logical checks performed in each stage are the same - i.e. everything I'm going to describe below. If any errors are found in the critical system tables (remember these from &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/19/636410.aspx"&gt;Part 1&lt;/A&gt;?) and:&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;repair is not specified; or, 
&lt;LI&gt;repair is specified, but not all the errors can be repaired&lt;/LI&gt;&lt;/UL&gt;
&lt;DIV&gt;then the CHECKDB finishes. An example of an unrepairable system table error is something that would require deleting data from one of the system tables - e.g. a corrupt key value in a clustered index data page of &lt;EM&gt;sysallocunits&lt;/EM&gt; (remember that this is the actual table I'm talking about, not the &lt;EM&gt;sys.allocation_units&lt;/EM&gt; catalog view you may have seen or used).&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;So if the system tables are clean, all the tables in the database are checked. This&amp;nbsp;includes indexed views and primary XML indexes (which are both stored as clustered indexes - and&amp;nbsp;as far as the storage engine is concerned&amp;nbsp;are objects in their own right - its the relational layer that knows that they're not &lt;EM&gt;really&lt;/EM&gt; separate objects).&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;The following checks are performed:&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;Validate each table's storage engine metadata 
&lt;LI&gt;Read and check all data, index and text pages, depending on the page type 
&lt;LI&gt;Check all inter-page relationships 
&lt;LI&gt;Check the page header counts 
&lt;LI&gt;Perform any necessary repairs&lt;/LI&gt;&lt;/UL&gt;
&lt;DIV&gt;Let's look at each of these stages in more detail.&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;&lt;STRONG&gt;Validate each table's storage engine metadata&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;Why do we need to do this? Well, the storage engine metadata is what tells CHECKDB how to crack open records on pages in particular rowsets - so if there's something wrong with it then CHECKDB will generate a bunch of&amp;nbsp;misleading errors or, worse yet,&amp;nbsp;miss some errors. Here's roughly what happens while the metadata is parsed:&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;Loop through all the indexes, and then all the rowsets of each index, building a list of known allocation units for the index (including all the DATA, LOB, and SLOB allocation units). This allows reverse lookups - when we read a page, because the information stamped on the page is the allocation unit, we need a very fast way to convert between an allocation unit and an index/object ID. 
&lt;LI&gt;Make sure we skip any indexes that are in the middle of being built/rebuilt online, because they will not have a complete set of data. 
&lt;LI&gt;Build a list of computed columns and generate the necessary code to enable the column values to be recomputed. 
&lt;LI&gt;Build a list of columns that are used in non-clustered indexes 
&lt;LI&gt;Make sure the various USED, DATA, RSVD counts are not negative&amp;nbsp;(see the BOL for DBCC CHECKDB for an explanation of how this can happen - yes, I'm deliberately not explaining here so that you read through the new BOL entry :-) 
&lt;LI&gt;Figure out what each kind of column is (e.g. a regular column, a generated uniquifier, a dropped column) 
&lt;LI&gt;Build a series of mappings to allow conversion between column IDs at different levels of storage abstraction 
&lt;LI&gt;Check that the relational and storage-engine nullability flags for a column agree 
&lt;LI&gt;Make sure the columns counters in metadata match what we've just seen&lt;/LI&gt;&lt;/UL&gt;
&lt;DIV&gt;&lt;STRONG&gt;Read and check all data, index and text pages&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;No matter what type a page is, the page is audited and then all the records on it are audited.&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;Page audit checks first of all for IO errors when the page is read (e.g. &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/29/Enabling_CHECKSUM_in_SQL2005.aspx"&gt;page checksums or torn-page detection&lt;/A&gt;). If there are some, then the page is not processed any further. This is what can lead to errors like 8976 being reported (e.g. &lt;FONT face="Courier New"&gt;Table error: Object ID 132765433, index ID 1, partition ID 72057594038321152, alloc unit ID 72057594042318848 (type DATA). Page (1:3874) was not seen in the scan although its parent (1:3999) and previous (1:3873) refer to it. Check any previous errors.&lt;/FONT&gt;). Then it checks for page header correctness and that the page has an appropriate type for the allocation unit its in (e.g. a DATA page should not be found in&amp;nbsp; an allocation unit for a non-clustered index)&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;Record audits include checking the various fields in the record header and that the various offsets in the record make sense (e.g. the offset to the variable length columns section of the record should not point off the end of the record. See the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/08/09/692806.aspx"&gt;post&lt;/A&gt;&amp;nbsp;on cracking records using DBCC PAGE for more info on the record format.&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;The more complex checks that are done per-page depend on what type the page is. As an example, here's what is done for a DATA page in the leaf level of a clustered index (excluding the inter-page relationships - I'll list those in the next section):&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;Records in a page must be strictly ordered by the defined keys of the index (although the records themselves aren't necessarily stored in sorted order in the data portion of the page, accessing the records through the slot array must yield them in the correct order) 
&lt;LI&gt;No two records can have duplicate key values (remember that non-unique indexes have a hidden, automatically-generated uniquifier column added to the key - to make or extend the composite key - so that record uniqueness is guaranteed) 
&lt;LI&gt;If the index is partitioned, each record is run through the partitioning function to ensure its stored in the correct partition 
&lt;LI&gt;All the complex columns in each record are checked: 
&lt;UL&gt;
&lt;LI&gt;Complex columns are those storing legacy text or LOB values (&lt;FONT face="Courier New"&gt;text&lt;/FONT&gt;, &lt;FONT face="Courier New"&gt;ntext,&lt;/FONT&gt; &lt;FONT face="Courier New"&gt;image&lt;/FONT&gt;, &lt;FONT face="Courier New"&gt;XML&lt;/FONT&gt;, &lt;FONT face="Courier New"&gt;nvarchar(max)&lt;/FONT&gt;, &lt;FONT face="Courier New"&gt;varchar(max)&lt;/FONT&gt;, &lt;FONT face="Courier New"&gt;varbinary(max)&lt;/FONT&gt;) or in-row pointers to variable length columns that have been pushed off-row in rows that are longer than 8060 bytes 
&lt;LI&gt;The column is checked to make sure its storing the right kind of data - either the value itself or a text pointer or some kind of in-row root containing pointers to portions of an off-row value. 
&lt;LI&gt;The linkages between what is stored in-row and the off-row values stored in other pages are eventually checked too&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;Check computed columns 
&lt;UL&gt;
&lt;LI&gt;If the column is persisted (either because its defined as a persisted computed column or because its used as a non-clustered index key), its value is recomputed and checked against the persisted value 
&lt;LI&gt;This is also important when we come to do the non-clustered index cross-checks - as any discrepancy in the stored column values will cause mismatches.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;Data purity checks 
&lt;UL&gt;
&lt;LI&gt;The column value is checked to ensure its within the bounds for its data-type (e.g. the minutes-past-midnight portion of the internal representation of a datetime value cannot be greater than 1440 - 24 hours x 60 minutes)&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;Non-clustered index cross-checks &lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This is probably my favorite part of CHECKDB and is one of the most complicated bits of code. 
&lt;LI&gt;What CHECKDB is trying to do is make sure that each record in a heap or clustered index has exactly one matching record in each non-clustered index, and vice-versa. The brute-force (n-squared complexity) way to do this is to do a physical lookup of all the matching rows - but that's incredibly time consuming so instead we have a fast algorithm to detect problems. 
&lt;LI&gt;Imagine a table defined by the following DDL:&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;SPAN style="COLOR: yellow; FONT-FAMILY: Courier; text-shadow: auto"&gt;&lt;FONT face="Courier New" color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE TABLE t (c1 INT, c2 char(10), c3 varchar(max))&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="COLOR: yellow; FONT-FAMILY: Courier; text-shadow: auto"&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: yellow; FONT-FAMILY: Courier; text-shadow: auto"&gt;&lt;FONT face="Courier New" color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE INDEX index1 ON t (c1)&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="COLOR: yellow; FONT-FAMILY: Courier; text-shadow: auto"&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: yellow; FONT-FAMILY: Courier; text-shadow: auto"&gt;&lt;FONT face="Courier New" color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE INDEX index2 ON t (c2) INCLUDE (c3)&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;UL&gt;
&lt;UL&gt;
&lt;LI&gt;Each row in the heap has to have two matching non-clustered index rows, on in each of &lt;FONT face="Courier New"&gt;index1&lt;/FONT&gt; and &lt;FONT face="Courier New"&gt;index2&lt;/FONT&gt;. But how can we tell without doing the direct lookup or having to store tremendous amounts of state? We use a hash-bitmap algorithm. 
&lt;LI&gt;Imagine a large bitmap - say half a million bits. Initially all the bits are zero. 
&lt;LI&gt;For each record in the heap that we come across, we generate the matching non-clustered index records and hash them to a value. This is very quick because we have all the column values we need. We then take the hash value, map it directly to a bit in the bitmap and flip the bit. So in our example above, each record in the heap will produce two hash values (one for the record in each non-clustered index) and so will cause two bits to be flipped. 
&lt;LI&gt;For each record in each non-clustered index, just hash the record and flip the corresponding bit. 
&lt;LI&gt;The idea is that the bit-flips should cancel each other out and the bitmap should be left with all zeroes at the end of the checks. 
&lt;LI&gt;Taking the view that corruptions are magnitudes rarer than clean databases, we went a step further and allowed the checks for multiple tables to use the same bitmap. If you think about it, this won't cause any problems, even if two sets of records map to the same bit in the bitmap - as long as the number of bit-flips is a power of 2 (i.e. each record really does have its correct matching record) then there should be no problem. 
&lt;LI&gt;Here's the catch - what happens when there's a bit left on in the bitmap? Well, this is where the trade-off comes into play. If there's a bit left on, we can't tell which records in which table or index mapped to it so, we have to re-scan the tables and indexs that used the bitmap to see which records map to the bit. For every one we find, we actually do the physical lookup of the matching record and then do a comparison of all the columns, including any LOB columns used as &lt;FONT face="Courier New"&gt;INCLUDE'&lt;/FONT&gt;d columns in non-clustered indexes. This process is called the &lt;EM&gt;deep-dive&lt;/EM&gt; and can add a significant amount to the run-time of CHECKDB if it occurs. &lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;DIV&gt;&lt;STRONG&gt;Check all inter-page relationships&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;Inter-page relationships are relevant for:&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;pages in heaps that have forwarding or forwarded records 
&lt;LI&gt;pages in indexes 
&lt;LI&gt;pages that have records with LOB columns that have their data stored off-row (these can be heap pages, clustered index data pages or non-clustered index leaf&amp;nbsp;pages in SQL Server 2005) 
&lt;LI&gt;text pages that have records with child nodes on other pages&lt;/LI&gt;&lt;/UL&gt;
&lt;DIV&gt;Continuing the example above, here are the checks that are done for index pages:&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;All pages in an index level should be pointed to by a page in the next level higher in the b-tree, and also by the left- and right-hand neighboring pages in the same level of the b-tree. Exceptions are made for the left-most and right-most pages in a level (where the &lt;FONT face="Courier New"&gt;m_prevPage&lt;/FONT&gt; and &lt;FONT face="Courier New"&gt;m_nextPage&lt;/FONT&gt; fields are &lt;FONT face="Courier New"&gt;(0:0)&lt;/FONT&gt;) and for the root page of the b-tree, where the parent page link comes from the storage-engine metadata. The 8976 error message that I referenced above is generated from this set of checks. 
&lt;LI&gt;Key ranges in neighboring pages in a level should not overlap 
&lt;LI&gt;Key ranges of pages should be correctly defined by the parent pages in the next level up in the b-tree (the parent pages contain the minimum key value that can exist on a child page)&lt;/LI&gt;&lt;/UL&gt;
&lt;DIV&gt;I'll go into details of how the inter-page checks are done in a future post. For now, its enough to say that its not an n-squared complexity algorithm.&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;&lt;STRONG&gt;Check the page header counts&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;The page header contains a bunch of counters - the ones we need to check are:&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;slot count 
&lt;LI&gt;ghost record count 
&lt;LI&gt;free space count&lt;/LI&gt;&lt;/UL&gt;
&lt;DIV&gt;The first two are obvious - count the rows as they're processed and make sure page header counts are valid. The free space count is only checked for text pages and data pages in a heap (the only pages for which free space&amp;nbsp;is tracked in a PFS page).&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;&lt;STRONG&gt;Perform any necessary repairs&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;I want to leave discussing repairs for another post as there's a ton of info there.&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;So, that's the majority of the work in running a DBCC CHECKDB and now its time for my session on choosing an HA solution in SQL Server 2005. Next time I'll post the next part of the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/category/13747.aspx"&gt;Fragmentation series&lt;/A&gt;.&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;&lt;EM&gt;(So I mentioned jellyfish above... I was having a meal last night with Scott Schnoll from the Exchange team and we had what we thought were noodles on the side of one dish. Scott asked what kind of noodles they were and then we found out we'd been eating cold, sliced jellyfish - it was really very tasty!)&lt;/EM&gt;&lt;/DIV&gt;
&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV&gt;&lt;STRONG&gt;Service Broker checks&lt;/STRONG&gt;&lt;BR&gt;&lt;STRONG&gt;Metadata cross-checks&lt;/STRONG&gt;&lt;BR&gt;&lt;STRONG&gt;Indexed view and XML index checks&lt;/STRONG&gt;&lt;BR&gt;(Part 4...)&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=761287" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category></item><item><title>Don't try this at home kids... (data recovery using DBCC PAGE)</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/08/09/693625.aspx</link><pubDate>Wed, 09 Aug 2006 22:41:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:693625</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/693625.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=693625</wfw:commentRss><description>&lt;P&gt;Time to cough up a real-life data recovery scenario to temporarily stop those people who badger me relentlessly for scenarios...&lt;/P&gt;
&lt;P&gt;We have a situation currently with a customer who managed to delete all their data during a SAN reconfig and then found out that their tape backups hadn't been working properly (the same sad story I've heard a thousand times). They did have a primary filegroup backup plus a backup of a secondary filegroup from a different point. This is on SQL Server 2005.&lt;/P&gt;
&lt;P&gt;The backups are restored, but the storage engine metadata for the table with the critical data in is messed up - &lt;FONT face="Courier New"&gt;sys.allocunits&lt;/FONT&gt; somehow has the wrong allocation unit IDs, first page, and root pages. So, what the hell can you do?&lt;/P&gt;
&lt;P&gt;Easy (and fun if you're twisted like me).&lt;/P&gt;
&lt;P&gt;We need to find the following info for the data allocation unit:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;the page ID of the head of the IAM chain for the allocation unit 
&lt;LI&gt;the root page of the clustered index 
&lt;LI&gt;the first page of the clustered index&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;And there's a twist, the table has a column of type &lt;EM&gt;image&lt;/EM&gt; so we also need to find the allocation unit ID and page ID of the head of the IAM chain for the LOB allocation unit.&lt;/P&gt;
&lt;P&gt;The easiest way to do this is to scan through the data files, doing &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt;s of every page and storing the results in a table for later analysis. How? Ah, there's something I haven't told you about &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; - it has a &lt;FONT face="Courier New"&gt;WITH TABLERESULTS&lt;/FONT&gt; option.&lt;/P&gt;
&lt;P&gt;So, setup a simple script to&amp;nbsp;&lt;FONT face="Courier New"&gt;INSERT/EXEC&lt;/FONT&gt; a&amp;nbsp;&lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; of every page with option 0 (for speed, otherwise it has to take the time to go through and crack and format every record on every page) and save the results to a table.&lt;/P&gt;
&lt;P&gt;To find the root page of the clustered index, query the table for the page with &lt;FONT face="Courier New"&gt;m_type = 2&lt;/FONT&gt; (an index page) and the highest &lt;FONT face="Courier New"&gt;m_level&lt;/FONT&gt;. The level number increases from the leaf of the b-tree to the root page, so the page with the highest level is the root.&lt;/P&gt;
&lt;P&gt;To find the first page, crack open the first record on the root page, and extract the page ID of the child page that the index record points to. This is the left-hand edge of the next level lower in the b-tree. Continue doing this until you find the page with &lt;FONT face="Courier New"&gt;m_level = 0&lt;/FONT&gt;. (Note that on SQL Server 2000, you'll need to look for &lt;FONT face="Courier New"&gt;m_level = 0&lt;/FONT&gt; AND &lt;FONT face="Courier New"&gt;m_type = 1&lt;/FONT&gt; - this is because pages at the leaf level and the level above in a SQL Server 2000 clustered index all have &lt;FONT face="Courier New"&gt;m_level = 0&lt;/FONT&gt;).&lt;/P&gt;
&lt;P&gt;To find the head of the IAM chain is a little trickier. You need to find any page with &lt;FONT face="Courier New"&gt;m_type = 10&lt;/FONT&gt; and following the &lt;FONT face="Courier New"&gt;m_prevPage&lt;/FONT&gt; links until its NULL. Then do an option 3 dump of the page and ensure that the &lt;FONT face="Courier New"&gt;sequenceNumber&lt;/FONT&gt; in the IAM page header is 0 (remember that an IAM chain is ordered by the sequence numbers in the IAM pages).&lt;/P&gt;
&lt;P&gt;Cool - we've done the clustered index.&lt;/P&gt;
&lt;P&gt;Now for the LOB allocation unit. Crack any row at the leaf level of the clustered index. You'll see that one of the columns is a text pointer, containing a page ID and slot number of the text fragment in the LOB allocation unit. Do a &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; of that page and now you know the allocation unit ID of the LOB allocation unit and can use the methodology above to find the head of its IAM chain.&lt;/P&gt;
&lt;P&gt;Now all you have to do is alter the hidden and unbindable &lt;FONT face="Courier New"&gt;sys.allocunits&lt;/FONT&gt; table to contain the correct data... Who's buying the beer?&amp;nbsp;:-)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=693625" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/On-Disk+Structures/default.aspx">On-Disk Structures</category></item><item><title>Poking about with DBCC PAGE (Part 1 of ?)</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/08/09/692806.aspx</link><pubDate>Wed, 09 Aug 2006 04:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:692806</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/692806.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=692806</wfw:commentRss><description>&lt;P&gt;&lt;EM&gt;(It's been a while since I last posted - summer fun's been in the way obviously and I've been busy picking up some new and exciting (for me) SQL skills, partially to help with four upcoming TechEds I'll be doing in China and Hong Kong. The posting frequency should increase towards the end of the week but in the meantime, this one's a special request.)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;I've been getting lots of requests for more info about how to use &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; since my &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/10/625659.aspx"&gt;Paul-tells-all post&lt;/A&gt; a while back and I had&amp;nbsp;been planning to wait until I'd posted more about the internals of &lt;FONT face="Courier New"&gt;DBCC CHECKDB&lt;/FONT&gt; and moved on to various examples of corruptions before starting to use &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; again in the blog. However, a friend made me an offer I couldn't refuse and so I've caved in and I'm starting the series now :-)&lt;/P&gt;
&lt;P&gt;I'm going to start with cracking a record from scratch. Yes, I know that option 3 of &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; will do it for you - but how does it do it? Sometimes you may not have table metadata and so &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; won't be able to use option 3 - in that case you'll need to crack it yourself. Also, there are plenty of curious people who like to be immersed in the bits and bytes and besides, cracking records manually is fun (if you're twisted as well as curious like I am&amp;nbsp;:-)&lt;/P&gt;
&lt;P&gt;I've created an example database, &lt;EM&gt;dbccpagetest&lt;/EM&gt;,&amp;nbsp;on SQL Server 2005 which I've zipped up and attached to this post. This way you can all use the same data and pages as me without having to go through the tedium of working out where pages are using the PFS pages (as I explained in the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/10/625659.aspx"&gt;initial &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; post&lt;/A&gt;).&lt;/P&gt;
&lt;P&gt;You won't be able to attach it to SQL Server 2000 but you can always download &lt;A href="http://msdn.microsoft.com/vstudio/express/sql/download/"&gt;SQL Server 2005 Express Edition&lt;/A&gt; and play with it on that. Unzip the files and attached them using the &lt;FONT face="Courier New"&gt;CREATE DATABASE ... FOR ATTACH&lt;/FONT&gt; syntax:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;CREATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;DATABASE&lt;/FONT&gt;&lt;FONT size=2&gt; dbccpagetest&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;ON&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FILENAME&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\dbccpagetest.mdf'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;FOR&lt;/FONT&gt;&lt;FONT size=2&gt; ATTACH;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;GO&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Note that if the filenames haven't changed since they were created, you only need to specify the primary file in the &lt;FONT face="Courier New"&gt;CREATE DATABASE&lt;/FONT&gt; statement. Very cool.&lt;/P&gt;
&lt;P&gt;The database has a single table with&amp;nbsp;a couple of rows, created using the following T-SQL:&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;CREATE&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;TABLE&lt;/FONT&gt;&lt;FONT size=2&gt; example &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;destination &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VARCHAR&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;activity &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VARCHAR&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;100&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;),&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;duration &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INT&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; example &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'Banff'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'sightseeing'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 5&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;INSERT&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INTO&lt;/FONT&gt;&lt;FONT size=2&gt; example &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'Chicago'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#ff0000 size=2&gt;'sailing'&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; 4&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;);&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;GO&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;The data page is page (1:152). Dumping that page using option 3 will give output including:&lt;/P&gt;&lt;FONT size=1&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Slot 0 Offset 0x60 Length 33&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Memory Dump @0x44DFC060&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;00000000: 30000800 05000000 0300f802 00160021 †0..............! &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;00000010: 0042616e 66667369 67687473 6565696e †.Banffsightseein &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;00000020: 67†††††††††††††††††††††††††††††††††††g &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Slot 0 Column 0 Offset 0x11 Length 5&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;destination = Banff &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Slot 0 Column 1 Offset 0x16 Length 11&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;activity = sightseeing &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Slot 0 Column 2 Offset 0x4 Length 4&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;duration = 5 &lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Previously&amp;nbsp;(&lt;EM&gt;that word always makes me think of Twin Peaks - 'Previously in Twin Peaks...', but I digress...)&lt;/EM&gt; I'd posted about the structure of a record - here it is again:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;record header 
&lt;UL&gt;
&lt;LI&gt;4 bytes long 
&lt;LI&gt;two bytes of record metadata (record type) 
&lt;LI&gt;two bytes pointing forward in the record to the NULL bitmap&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;fixed length portion of the record, containing the columns storing data types that have fixed lengths (e.g. &lt;EM&gt;bigint&lt;/EM&gt;, &lt;EM&gt;char(10)&lt;/EM&gt;, &lt;EM&gt;datetime&lt;/EM&gt;) 
&lt;LI&gt;NULL bitmap 
&lt;UL&gt;
&lt;LI&gt;two bytes for count of columns in the record 
&lt;LI&gt;variable number of bytes to store one bit per column in the record, regardless of whether the column is nullable or not 
&lt;LI&gt;this allows an optimization when reading columns that are NULL (see &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/29/650349.aspx"&gt;here&lt;/A&gt; for more info)&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;variable-length column offset array 
&lt;UL&gt;
&lt;LI&gt;two bytes for the count of variable-length columns 
&lt;LI&gt;two bytes per variable length column, giving the offset to the start of the column valu&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;versioning tag 
&lt;UL&gt;
&lt;LI&gt;this is in SQL Server 2005 only 
&lt;LI&gt;this is a 14-byte structure that contains a timestamp plus a pointer into the version store in tempdb&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;So, let's go through the record from the dump fragment above and figure out what everything means. I'm not going to give all the excruciating detail on every possible value of every byte, but will give you enough to be able to crack records yourself (if you're twisted like me...)&lt;/P&gt;
&lt;P&gt;Byte 0 is the TagA byte of the record metadata. Its &lt;FONT face="Courier New"&gt;0x30&lt;/FONT&gt;, which corresponds to &lt;FONT face="Courier New"&gt;0x10&lt;/FONT&gt; (bit 4) and &lt;FONT face="Courier New"&gt;0x20&lt;/FONT&gt; (bit 5). Bit 4 means the record has a NULL bitmap and bit 5 means the record has variable length columns. If &lt;FONT face="Courier New"&gt;0x40&lt;/FONT&gt; (bit 6) was also set, that would indicate that the record has a versioning tag. If &lt;FONT face="Courier New"&gt;0x80&lt;/FONT&gt; (bit 7) was also set, that would indicate that byte 1 has a value in it.&lt;/P&gt;
&lt;P&gt;Bits 1-3 of byte 0 give the record type. The possible values are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;0 = primary record 
&lt;UL&gt;
&lt;LI&gt;a data record in a heap that hasn't been forwarded or a data record at the leaf level of a clustered index.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;1 = forwarded record 
&lt;UL&gt;
&lt;LI&gt;a data record in a heap that's been updated and was too large to fit in-place on its original page and so has been moved to another page. A forwarding record is left in its place and points to the new location of the record. This is done to avoid having to update any non-clustered index records that point back directly to the original physical location of the record.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;2 = forwarding record 
&lt;UL&gt;
&lt;LI&gt;sometimes also called a forwarding stub.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;3 = index record 
&lt;UL&gt;
&lt;LI&gt;an index record in the tree of a clustered index, or in any level of a non-clustered index.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;4 = blob fragment 
&lt;LI&gt;5 = ghost index record 
&lt;LI&gt;6 = ghost data record 
&lt;UL&gt;
&lt;LI&gt;these two are self-explanatory&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;7 = ghost version record 
&lt;UL&gt;
&lt;LI&gt;a special 15-byte record containing a single byte record header plus a 14-byte versioning tag that is used in some circumstances (like ghosting a versioned blob record)&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;In our example, none of these bits are set which means the record is a primary record. If the record was an index record, byte 0 would have the value &lt;FONT face="Courier New"&gt;0x36&lt;/FONT&gt;. Remember that the record type starts on bit 1, not bit 0, and so the record type value from the enumeration above needs to be shifted left a bit (multiplied by two) to get its value in the byte.&lt;/P&gt;
&lt;P&gt;Byte 1 is the TagB byte of the record metadata. It can either be &lt;FONT face="Courier New"&gt;0x00&lt;/FONT&gt; or &lt;FONT face="Courier New"&gt;0x01&lt;/FONT&gt;. If it is &lt;FONT face="Courier New"&gt;0x01&lt;/FONT&gt;, that means the record type is ghost forwarded record. In this case its &lt;FONT face="Courier New"&gt;0x00&lt;/FONT&gt;, which is what we expect given the TagA byte value.&lt;/P&gt;
&lt;P&gt;Bytes 2 and 3 are the offset of the NULL bitmap in the record. This is &lt;FONT face="Courier New"&gt;0x0008&lt;/FONT&gt; (&lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; presents multi-byte values in hex dumps as least-significant byte first). This means that there's a 4-byte fixed length portion of the record starting at byte 4. We expect this because we know the table schema.&lt;/P&gt;
&lt;P&gt;Bytes 4 to 7 are the fixed length portion. Again, because we know the table schema, we know to interpret these bytes as a 4-byte integer. Without that knowledge, you'd have to guess. The value therefore is &lt;FONT face="Courier New"&gt;0x00000005&lt;/FONT&gt;, which is what we'd expect to see as the value of the &lt;EM&gt;duration&lt;/EM&gt; column.&lt;/P&gt;
&lt;P&gt;Bytes 8 and 9 are the count of columns in the record. This is &lt;FONT face="Courier New"&gt;0x0003&lt;/FONT&gt; which is correct. Given that there are only 3 columns, the NULL bitmap of one bit per column will fit in a single byte.&lt;/P&gt;
&lt;P&gt;Byte 10 is the NULL bitmap. Hey - it's value is &lt;FONT face="Courier New"&gt;0xF8&lt;/FONT&gt; - what's up with that? Convert it to binary and what do you get? &lt;FONT face="Courier New"&gt;11111000&lt;/FONT&gt; This makes perfect sense - bits 0-2 represent columns 1-3 and they're all 0, meaning the columns aren't NULL. Bits 3-7 represent non-existent columns and they're set to 1 for clarity. So the &lt;FONT face="Courier New"&gt;0xF8&lt;/FONT&gt; value makes sense - phew.&lt;/P&gt;
&lt;P&gt;Bytes 11 and 12 are the count of variable length columns in the record. That value is &lt;FONT face="Courier New"&gt;0x0002&lt;/FONT&gt;, which we again know to be correct. This means there will be two two-byte entries in the variable length column offset array. These will be bytes 13-14 and 15-16, having values of &lt;FONT face="Courier New"&gt;0x0016&lt;/FONT&gt; and &lt;FONT face="Courier New"&gt;0x0021&lt;/FONT&gt; respectively.&lt;/P&gt;
&lt;P&gt;Now, the explanation that the variable length column offset array stores the offsets to the start of the column value is over-simplified. The entries actually point to the start of the following column value - this is done so that we know how long each column is (they are variable length after all). Notice that the offset of the first variable length column value isn't stored - it doesn't need to be because by definition it must begin right after the last offset in the variable length column offset array.&lt;/P&gt;
&lt;P&gt;So, the final offset is bytes 15 and 16, which means the offset of the start of the first variable length column must be byte 17 (or 0x11 in hex), which agrees with the &lt;FONT face="Courier New"&gt;DBCC PAGE&lt;/FONT&gt; dump. The offset of the second variable length column is &lt;FONT face="Courier New"&gt;0x0016&lt;/FONT&gt;, so the first value is from byte 17 to byte 21 inclusive. This value is &lt;FONT face="Courier New"&gt;0x42616E6666&lt;/FONT&gt;. We know from the table metadata that this is&amp;nbsp;the first&amp;nbsp;varchar column, &lt;EM&gt;destination&lt;/EM&gt;. Checking our handy &lt;A href="http://en.wikipedia.org/wiki/ASCII"&gt;ASCII conversion table&lt;/A&gt;&amp;nbsp;we find that this translates to '&lt;FONT face="Courier New"&gt;Banff&lt;/FONT&gt;'.&lt;/P&gt;
&lt;P&gt;Using similar logic, the second value is from byte 22 to byte 32 inclusive and has the value '&lt;FONT face="Courier New"&gt;sightseeing&lt;/FONT&gt;'. Both of these match the data we're expecting.&lt;/P&gt;
&lt;P&gt;And that's it. We've just cracked a record from scratch. Now you try it with the second row in the table. In future posts I'll start making things more complicated (maybe trace into the version store or add in some off-row LOB values).&lt;/P&gt;
&lt;P&gt;Hopefully this will satisfy all of those who've been waiting for more info on using DBCC PAGE and now I'm looking forward to getting my side of the bargain from my friend...&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=692806" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/sqlserverstorageengine/attachment/692806.ashx" length="1075145" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/On-Disk+Structures/default.aspx">On-Disk Structures</category></item><item><title>Can't I ever get a guarantee?</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/07/23/675963.aspx</link><pubDate>Sun, 23 Jul 2006 21:19:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:675963</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/675963.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=675963</wfw:commentRss><description>&lt;P&gt;I've been sitting and thinking a lot about guarantees this morning while drinking coffee in the debilitating heat here (85 degrees at 11am) and things get&amp;nbsp;more complicated the more I think about it, so time to stop and post some thoughts.&lt;/P&gt;
&lt;P&gt;Over the last few days, the question of guarantees has come up several times in various forums, essentially -&amp;nbsp;&lt;EM&gt;what guarantee do I get from a clean CHECKDB run?&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;The simple answer is 'not much', but let me go into more detail.&lt;/P&gt;
&lt;P&gt;Here's an analogy to help illustrate my point. Consider Paul, who works for the Seattle Police Department in traffic control. Paul's in a control room somewhere in the city with a large bank of monitors connected to various highway cameras. Every 1/2 hour Paul cycles through the various cameras feeds looking for problems. At the end of the 1/2 hour cycle, Paul knows that there are no accidents in the city.&lt;/P&gt;
&lt;P&gt;Ah - but hold on. Does Paul really know that? No. All Paul knows is that at the point he looked at a particular camera, there was not an accident at that spot in the highway network. The very instant he switches to another camera feed, an accident could happen at spot covered by the previous camera.&lt;/P&gt;
&lt;P&gt;Hopefully you're starting to see where I'm going with this analogy. A database page is known good at the point that its read from disk. After that point, &lt;EM&gt;anything&lt;/EM&gt; could happen to it, the very next millisecond after the page read has completed.&lt;/P&gt;
&lt;P&gt;So, when a CHECKDB completes cleanly, you know that the set of database pages that were read were clean at the point they were read. You can't even say that the entire database is clean at any instant of time, because its not possible to read an entire database in an instant of time.&lt;/P&gt;
&lt;P&gt;Now, this may come as a shock to some people reading this but really it shouldn't - its common sense. Basically, there's no &lt;EM&gt;guarantee&lt;/EM&gt; of any future lack of corruptions. You can say that with good, well-behaving and up-to-date hardware the likelihood of future corruptions is small, but you can't &lt;EM&gt;guarantee&lt;/EM&gt; it.&lt;/P&gt;
&lt;P&gt;An extrapolation of this point applies to database backups. A common sequence of events is to run a CHECKDB, take a backup, restore the backup on another system and then run a CHECKDB on the resulting database. Yes, this gives you a good sense that the database was clean before it was backed up, the backup worked, and what's contained in the backup is a clean database - but that's where it ends. At the instant that the final CHECKDB completes, you still don't have any &lt;EM&gt;guarantees&lt;/EM&gt;. Something could happen to the backup file - you could have a double failure of the original database and the backup file. Unlikely, sure, but perfectly possible and I've seen it happen many times.&lt;/P&gt;
&lt;P&gt;So now that I've scared the hell out of&amp;nbsp;some of you&amp;nbsp;reading this, I'd better touch on the questions that you're no-doubt asking yourselves:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;What's the point of running CHECKDB then?&lt;/LI&gt;
&lt;LI&gt;What can I do to get closer to a guarantee?&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;#1 is the easier to answer. Although you don't get any future guarantees from a clean CHECKDB run, you do at least know that everything's good at present and that all database pages could be cleanly read from disk. That's a pretty strong reassurance that your hardware is holding up.&lt;/P&gt;
&lt;P&gt;How often to run a CHECKDB (or combination of other check commands) is way more complicated, and is a subject for a seperate blog post (yes, all those people who keep asking me to post about this - I'll get to it eventually :-)&lt;/P&gt;
&lt;P&gt;#2 has no easy answer and I could easily fill a book writing about high availability and disaster recovery. However, I'm not going to do that yet so here&amp;nbsp;are some simple things off the top of my head for you to think about and investigate and I'll follow up with a bunch of blog postings over the next few months:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This is the most important one - if you really have mission-critical data, employ DBAs who have a clue what they're doing - I've seen some scarily naive people running things for large companies&lt;/LI&gt;
&lt;LI&gt;Convince those that control your budget of the consequences of not spending a little money to protect the data&lt;/LI&gt;
&lt;LI&gt;Ensure that all your drivers and firmware are up-to-date&lt;/LI&gt;
&lt;LI&gt;Run stress tests on your hardware to ensure that it can cope with the load that you may drive SQL Server to place on it&lt;/LI&gt;
&lt;LI&gt;Turn on page checksums in SQL Server 2005&lt;/LI&gt;
&lt;LI&gt;Run regular DBCCs to forcibly verify the integrity of all the database pages&lt;/LI&gt;
&lt;LI&gt;Use mirrored backups&lt;/LI&gt;
&lt;LI&gt;Use decent hardware to store mission critical data&lt;/LI&gt;
&lt;LI&gt;Investigate the various &lt;A href="http://www.microsoft.com/sql/alwayson/default.mspx"&gt;Always-On technologies&lt;/A&gt;&amp;nbsp;in SQL Server&lt;/LI&gt;
&lt;LI&gt;Practice your disaster recovery strategy&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Yes, there are plenty more things I could add to the list but I didn't mean it to be exhaustive.&lt;/P&gt;
&lt;P&gt;So, even though its not possible to get a guarantee,&amp;nbsp;I&amp;nbsp;should be&amp;nbsp;able to&amp;nbsp;get some degree of assurance that things are ok and will continue to be that way in the face of any eventuality - the trick is to think things through carefully and make appropriate choices.&lt;/P&gt;
&lt;P&gt;More on this early next week hopefully...&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=675963" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/Disaster+Recovery/default.aspx">Disaster Recovery</category></item><item><title>CHECKDB (Part 3): What does CHECKDB really do? (2 of 4)</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/07/18/670341.aspx</link><pubDate>Wed, 19 Jul 2006 01:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:670341</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/670341.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=670341</wfw:commentRss><description>&lt;P&gt;In the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/19/636410.aspx"&gt;previous post&lt;/A&gt; of this series, I covered the system table checks that have to be done before anything else can be checked by CHECKDB. Now that I've described &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/26/647005.aspx"&gt;pages&lt;/A&gt;, &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/28/649884.aspx"&gt;extents&lt;/A&gt;, &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx"&gt;IAM chains/allocation units&lt;/A&gt;&amp;nbsp;and the &lt;A href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/07/08/660071.aspx"&gt;major allocation bitmaps&lt;/A&gt;, in this post I'll cover the allocation checks.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;1. Primitive checks of critical system tables&lt;BR&gt;&lt;/STRONG&gt;(Part 1...)&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;STRONG&gt;2. Allocation checks&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This stage is in SQL Server 2000 and 2005. Allocation checks are checks of the various structures (IAM pages, IAM chains, allocation units, GAM/SGAM pages, PFS pages) that describe the allocations (pages, extents) that have been done within a database.&lt;/P&gt;
&lt;P&gt;I'll describe how we go about collecting information from the various pages and then describe what some of the actual checks are.&lt;/P&gt;
&lt;P&gt;The allocation checks are very fast (orders of magnitude faster than the logical checks, so fast in fact that they happen in the blink of an&amp;nbsp;eye! well, perhaps I'm&amp;nbsp;getting carried away&amp;nbsp;a little as usual but you get the idea) because the number of database pages that have to be read is very small (so small in fact that... ok, I'll shut-up).&amp;nbsp; The algorithm for gathering allocation data is as follows:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;For each file in each online filegroup in the database (except transaction log files):&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;read all PFS pages&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This gives us a bitmap showing all IAM pages, plus another one showing all mixed pages&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;read the GAM pages&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This gives us bitmaps of all allocated extents&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;read the SGAM pages&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This gives us bitmaps of all mixed extents with at least one unallocated page&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;read the DIFF_MAP pages (a &lt;EM&gt;'differential bitmap'&lt;/EM&gt; page shows which extents in the GAM interval have been modified since the last full or differential backup - a differential backup only needs to backup those extents marked modified in the various DIFF_MAP pages)&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This is just to make sure the pages can be read&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;read the ML_MAP pages (a &lt;EM&gt;'minimally-logged bitmap' &lt;/EM&gt;page shows which extents in the GAM interval have been modified in bulk-logged recovery mode since the last log backup - a log backup must also backup all such extents to ensure that all changes to the database have been backed up. This can make the log backup quite large (although the log itself stays much smaller) - but that's a topic for another blog post.&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This is just to make sure the pages can be read&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;read all IAM pages&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This gives us:&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;a list of all the mixed pages in the file, and by derivation, a list of all mixed extents in the file (remember that the first IAM page in an IAM chain/allocation unit&amp;nbsp;contains an array to hold up to 8 mixed pages for the object/index/partition it represents&lt;/LI&gt;
&lt;LI&gt;a list of all the valid IAM pages in the file&lt;/LI&gt;
&lt;LI&gt;a list of all the allocated dedicated extents in the file&lt;/LI&gt;
&lt;LI&gt;linkage information for IAM chains&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;LI&gt;After all the per-file stuff, read the Storage Engine metadata&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;This gives us:&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;information about the &lt;EM&gt;root&lt;/EM&gt; of each IAM chain. Each row in the sys.allocation_units hidden metadata table contains the page Id of the first IAM page in the IAM chain for that allocation unit.&lt;/LI&gt;
&lt;LI&gt;information about IAM chains currently waiting to be&lt;EM&gt; deferred-dropped.&lt;/EM&gt; (This is the process by which an IAM chain with &amp;gt; 128 extents that is dropped - by dropping/rebuilding an index or dropping/truncating a table - does not have its actual pages and extents deallocated until after the transaction has committed. The IAM chain is unhooked from sys.allocation_units though and hooked into an internal queue - if we didn't scan that queue too as part of the allocation checks, we'd see all kinds of inconsistencies with the various allocation bitmaps)&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;P&gt;So, now we've got a whole bunch of allocation data that we're juggling and we need to make sense of it all to see if all the allocation structures are correct. Here's a non-exhaustive list of checks that we do with all this data:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Check that each extent is either allocated to:&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;the GAM page for the GAM interval&lt;/LI&gt;
&lt;LI&gt;or, the SGAM page for the GAM interval, as a non-full mixed extent&lt;/LI&gt;
&lt;LI&gt;or, exactly one IAM page that covers the GAM interval&lt;/LI&gt;
&lt;LI&gt;or, to no bitmap page, but all pages in the extent must be allocated to IAM pages as mixed pages&lt;/LI&gt;
&lt;LI&gt;This could result in an 8903 (GAM and SGAM), 8904 (multiple IAMs), or 8905 (no&amp;nbsp;page)&amp;nbsp;errors depending on the combination of bitmaps that have the extent allocated&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;Check that all pages marked as being IAM pages in PFS pages really are IAM pages when they're read&lt;/LI&gt;
&lt;LI&gt;Check that all pages marked as being mixed pages in PFS pages appear somewhere in a mixed page array on an IAM page&lt;/LI&gt;
&lt;LI&gt;Check that each mixed page is only allocated in a single IAM page&lt;/LI&gt;
&lt;LI&gt;Check that the IAM pages in an IAM chain have monatonically increasing sequence numbers&lt;/LI&gt;
&lt;LI&gt;Check that the first IAM page in an IAM chain has a reference from a row in sys.allocation_units&lt;/LI&gt;
&lt;LI&gt;Check that no two IAM pages within the same IAM chain map the same GAM interval&lt;/LI&gt;
&lt;LI&gt;Check that all IAM pages within an IAM chain belong to the same object/index/partition&lt;/LI&gt;
&lt;LI&gt;Check that the linkages within an IAM chain are correct (no missing pages for instance)&lt;/LI&gt;
&lt;LI&gt;Check that all IAM/GAM/SGAM pages that map the final GAM interval in a file do not have extents marked allocated that are beyond the physical end of the file&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Any errors found here will require REPAIR_ALLOW_DATA_LOSS to repair and some of the repairs are very complicated (e.g. multiply-allocated extents) - topic for a future blog post.&lt;/P&gt;
&lt;P&gt;So, the allocation checks lay the next foundation level over the system table primitive checks and we're ready to move on to the logical checks.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;3. Logical checks of critical system tables&lt;BR&gt;4. Logical checks of all tables&lt;/STRONG&gt;&lt;BR&gt;(Part 3...)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;5. Service Broker checks&lt;BR&gt;6. Metadata cross-checks&lt;BR&gt;7. Indexed view and XML index checks&lt;/STRONG&gt;&lt;BR&gt;(Part 4...)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=670341" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category></item><item><title>CHECKDB (Part 2): What does CHECKDB really do? (1 of 4)</title><link>http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/19/636410.aspx</link><pubDate>Mon, 19 Jun 2006 04:09:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:636410</guid><dc:creator>Paul Randal - MSFT</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/sqlserverstorageengine/comments/636410.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlserverstorageengine/commentrss.aspx?PostID=636410</wfw:commentRss><description>&lt;P&gt;Hmmm - I sat for 5 minutes thinking of something amusing to say to start this one off and nothing came to mind, so I'm afraid this will be a humor-free post. Maybe I'm jet-lagged from being on the East coast all last week.&lt;/P&gt;
&lt;P&gt;As with all things related to DBCC, this topic has its share of misinformation. In this post I'll set the record straight by running through all the stages of CHECKDB in SQL Server 2000 and 2005. I'll need to split this up into seperate posts otherwise I'll be writing a book. I also introduce a whole raft of new terms which will also be subjects for future posts (my list is already getting pretty long!)&lt;/P&gt;
&lt;P&gt;So the very first thing it does is work out how to get the transactionally consistent view it requires (see &lt;A href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/09/623789.aspx"&gt;CHECKDB Part 1&lt;/A&gt;) and then, if needed, either record the relevant LSN and switch to full-logging (for SQL Server 2000) or create a database snapshot (for SQL Server 2005).&lt;/P&gt;
&lt;P&gt;Then it runs through the checks in the order shown below:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;1. Primitive checks of critical system tables&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This stage is in SQL Server 2000 and 2005. First of all, what are critical system tables? These are the system tables that hold Storage Engine metadata. Without these we'd have no idea where any data was stored in the database files or how to interpret records.&lt;/P&gt;
&lt;P&gt;In SQL Server 2000, the critical system tables are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;sysindexes&lt;/LI&gt;
&lt;LI&gt;sysobjects&lt;/LI&gt;
&lt;LI&gt;syscolumns&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;These tables have to be checked first because we use the metadata they contain to access all the other tables and indexes in the database. These tables are freely queryable so poke about and see what's stored in there.&lt;/P&gt;
&lt;P&gt;In SQL Server 2005, the metadata layer has been rewritten and the critical system tables are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;sysallocunits&lt;/LI&gt;
&lt;LI&gt;syshobts&lt;/LI&gt;
&lt;LI&gt;syshobtcolumns&lt;/LI&gt;
&lt;LI&gt;sysrowsets&lt;/LI&gt;
&lt;LI&gt;sysrowsetcolumns&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;More on allocation units, hobts, and rowsets later in the week - for now you can assume they serve the same function as the three critical system tables in SQL Server 2000. You can't see these system tables because they're 'hidden' - the parser won't allow them to be bound to in a query. Try running '&lt;FONT face="Courier New"&gt;select * from sysallocunits&lt;/FONT&gt;' to see what I mean.&lt;/P&gt;
&lt;P&gt;The primitive checks are designed to check that internal queries on the metadata tables won't throw errors. Each of the critical system tables has a clustered index. The primitive checks just check the leaf-level data pages of the clustered indexes. For every one of these pages, the following is done:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Read and latch the page (a latch is a lightweight internal version of a lock).&amp;nbsp; This makes sure that there aren't any IO problems with the page such as a torn-page or bad page checksum and&amp;nbsp;ensures that we can put the page in the buffer pool correctly. This is the most common cause of failure of the primitive system table checks and results in error 8966, which in SQL Server 2000 could look something like:&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT face="Courier New"&gt;Server: Msg 8966, Level 16, State 1, Line 1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Could not read and latch page (1:33245) with latch type SH. sysobjects failed.&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Audit the page. This is a series of checks of the page structures which I'll cover in a seperate post. If these pass, the page looks like a SQL Server page of type its supposed to be.&lt;/LI&gt;
&lt;LI&gt;Check the basic page linkage. Pages in each level of a clustered index are linked together in a doubly-linked list to allow range scans to work. At this stage we only check the left-to-right linkage to ensure the linked-to page actually exists.&lt;/LI&gt;
&lt;LI&gt;Check the page linkage for loops.&amp;nbsp;This is simple to do - have two pointers into the page linked-list with one advancing at every step and one advancing at every second step. If they ever point to the same thing before the faster-advancing pointer reaches the right-hand side of the leaf level then there's a loop. Its important that there are no linkage loops otherwise a range scan may turn into an infinite loop. I've never seen this occur in the field.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Any error found at this stage cannot be repaired&amp;nbsp;so you must restore from a backup. This is because the&amp;nbsp;repair would have to deallocate the page, effectively deleting metadata for a whole lot of tables and indexes. As people's databases get larger and more complex (thousands of tables and indexes), the percentage of pages that comprise these critical system tables rises and so the chance of a hardware problem corrupting one of these pages also rises - I see several of these a month on the forums. Without a backup, the only alternative is to try to export as much data as you can - not good.&lt;/P&gt;
&lt;P&gt;If all the pages are ok then we know we've got solid enough metadata on which to base the next set of checks.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;2. Allocation checks&lt;BR&gt;&lt;/STRONG&gt;(Part 2...)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;3. Logical checks of critical system tables&lt;BR&gt;4. Logical checks of all tables&lt;BR&gt;&lt;/STRONG&gt;(Part 3...)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;5. Service Broker checks&lt;BR&gt;6. Metadata cross-checks&lt;BR&gt;7. Indexed view and XML index checks&lt;BR&gt;&lt;/STRONG&gt;(Part 4...)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=636410" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC/default.aspx">DBCC</category><category domain="http://blogs.msdn.com/sqlserverstorageengine/archive/tags/DBCC+CHECKDB+Series/default.aspx">DBCC CHECKDB Series</category></item></channel></rss>