<?xml version="1.0" encoding="utf-8"?>
<feed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom">
  <title>In Recovery...</title>
  <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/" />
  <link rel="self" href="http://www.sqlskills.com/blogs/paul/SyndicationService.asmx/GetAtom" />
  <icon>favicon.ico</icon>
  <updated>2008-08-28T11:29:44.6965-07:00</updated>
  <author>
    <name>Paul S. Randal</name>
  </author>
  <subtitle>Paul Randal on SQL Server</subtitle>
  <id>http://www.sqlskills.com/blogs/paul/</id>
  <generator uri="http://www.dasblog.net" version="2.0.7180.0">DasBlog</generator>
  <entry>
    <title>RunAs Radio interview on being an "involuntary DBA"</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/28/RunAsRadioInterviewOnBeingAnInvoluntaryDBA.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,98df737a-c3d3-44a3-b2c5-a1140a90c425.aspx</id>
    <published>2008-08-28T11:28:45.243-07:00</published>
    <updated>2008-08-28T11:29:44.6965-07:00</updated>
    <category term="Database Maintenance" label="Database Maintenance" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Database%2BMaintenance.aspx" />
    <category term="Interviews" label="Interviews" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Interviews.aspx" />
    <category term="Jokes" label="Jokes" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Jokes.aspx" />
    <category term="Involuntary DBA" label="Involuntary DBA" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Involuntary%2BDBA.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
On Tuesday I recorded a couple of sessions with Richard and Greg on <a href="http://www.RunAsRadio.com">RunAs
Radio</a>. It's been a while since either Kimberly or I have been on the show - last
November at TechEd in Barcelona. In the first session we discussed what it is to be
an "involuntary DBA" - someone who's thrown into the DBA role with no training. This
goes along nicely with the TechNet Magazine article I wrote for the August 2008 issue
on <a href="http://www.sqlskills.com/blogs/paul/2008/07/08/TechNetMagazineEffectiveDatabaseMaintenanceArticleAndAugustSQLQAColumn.aspx">Effective
Database Maintenance</a> (for the involuntary DBA). Kimberly also pops in from time
to time when she's not coughing, we make fun of her, and I describe one of my favorite
Calvin and Hobbes cartoons around collecting spit in a jar - all the usual silliness.
</p>
          <p>
The show is 35 minutes long and you can download it at <a href="http://www.runasradio.com/default.aspx?showNum=72">http://www.runasradio.com/default.aspx?showNum=72</a>.
</p>
          <p>
Enjoy!
</p>
        </font>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=98df737a-c3d3-44a3-b2c5-a1140a90c425" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>This had me in tears laughing...</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/27/ThisHadMeInTearsLaughing.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,0937379d-00d0-4963-ad9d-a7ecdc8d5898.aspx</id>
    <published>2008-08-27T10:45:11.493375-07:00</published>
    <updated>2008-08-27T10:45:11.493375-07:00</updated>
    <category term="Personal" label="Personal" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Personal.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
Just go watch it - LEGO stop-go animation of a Metallica concert - it's fantastic!
</p>
          <p>
            <a href="http://www.sarahlacy.com:80/sarahlacy/2008/08/stop-what-you-a.html">http://www.sarahlacy.com:80/sarahlacy/2008/08/stop-what-you-a.html</a>
          </p>
          <p>
Thanks to <a href="http://www.statisticsio.com/">Jason Massie</a> for the heads-up
(tons of cool SQL stuff on Jason's site btw...)
</p>
        </font>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=0937379d-00d0-4963-ad9d-a7ecdc8d5898" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>Search Engine Q&amp;A #26: Myths around causing corruption</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/27/SearchEngineQA26MythsAroundCausingCorruption.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,6096d901-6322-4328-b62a-dc2b789aa9a5.aspx</id>
    <published>2008-08-27T10:11:27.54-07:00</published>
    <updated>2008-08-27T10:12:09.47775-07:00</updated>
    <category term="Bad Advice" label="Bad Advice" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Bad%2BAdvice.aspx" />
    <category term="CHECKDB From Every Angle" label="CHECKDB From Every Angle" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,CHECKDB%2BFrom%2BEvery%2BAngle.aspx" />
    <category term="Corruption" label="Corruption" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Corruption.aspx" />
    <category term="DBCC" label="DBCC" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,DBCC.aspx" />
    <category term="Indexes From Every Angle" label="Indexes From Every Angle" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Indexes%2BFrom%2BEvery%2BAngle.aspx" />
    <category term="IO Subsystems" label="IO Subsystems" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,IO%2BSubsystems.aspx" />
    <category term="On-Disk Structures" label="On-Disk Structures" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,On-Disk%2BStructures.aspx" />
    <category term="Repair" label="Repair" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Repair.aspx" />
    <category term="Search Engine Q and A" label="Search Engine Q and A" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Search%2BEngine%2BQ%2Band%2BA.aspx" />
    <category term="Shrink" label="Shrink" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Shrink.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
Every so often I'll see posts on the various data corruption forums discussing causes
of corruption. In this post I want to debunk some of the myths around what can cause
corruption. There are really two types of corruption to deal with, physical corruption
and logical corruption.
</p>
          <p>
            <strong>Physical corruption</strong>
          </p>
          <p>
This is where something has altered the contents of a data or log file sector with
no regard for what is being stored there. Possible causes of physical corruption are:
</p>
          <ul>
            <li>
Problem with the I/O subsystem (99.8% of all cases I've ever seen - only 3 nines
as I'd estimate I've seen around about a thousand corruption cases). Remember the
I/O subsystem is everything underneath SQL Server in the I/O stack - including the
OS, 3rd-party file system filter drivers, device drivers, RAID controllers, SAN controllers,
network hardware, drives themselves, and so on. Millions of lines of code and lots
of moving parts spinning very fast, very close to very fragile pieces of metal oxide
(I once heard Jim Gray liken a disk drive head to a 747 jumbo jet flying at 500 mph
at a height of 1/4 inch from the ground...) 
</li>
            <li>
Problem with the host machine hardware (0.1% of cases). Most of the time this is a
memory error. 
</li>
            <li>
SQL Server bugs (0.1% of cases). Yes, there have been corruption bugs. Every piece
of software has bugs. There are KB articles describing bugs. 
</li>
            <li>
Deliberate introduction of corruption using a hex editor or other means.</li>
          </ul>
          <p>
Physical corruption is what <font face="Courier New">DBCC CHECKDB</font> usually reports
and the majority of cases are caused by a physical failures of some kind, with the
minority caused by humans - software bugs.
</p>
          <p>
            <strong>Logical corruption</strong>
          </p>
          <p>
This is where something has altered some data so that a data relationship is broken.
Possible causes of logical corruption are:
</p>
          <ul>
            <li>
Humans</li>
          </ul>
          <p>
:-) Okay...
</p>
          <ul>
            <li>
Application bug. The application deletes one part of an inherent data relationship
but not the other. Or the application designer doesn't implement a constraint properly.
Or the application designer doesn't cope with a transaction roll-back properly. You
get the idea. 
</li>
            <li>
Accidental update/delete. Someone deletes or updates some data incorrectly. 
</li>
            <li>
SQL Server bug. See above. 
</li>
            <li>
              <font face="Courier New">DBCC CHECKDB</font> when using the <font face="Courier New">REPAIR_ALLOW_DATA_LOSS</font> option.
As is documented in Books Online, and I've blogged about and mentioned when lecturing,
if you run repair, it doesn't take into account any inherent or explicit constraints
on the data.</li>
          </ul>
          <p>
The point here is that a physical failure of a component does not cause logical corruption,
it causes physical corruption. Conversely, application errors cause logical corruption,
not physical corruption. <font face="Courier New">DBCC CHECKDB</font> errors are about
physical corruption (okay, with the inclusion of <font face="Courier New">DBCC CHECKCATALOG</font> code
in 2005, it will find cases where the DBA has manually altered the system tables,
causing logical corruption) and applications cannot cause physical corruption as they
can only manipulate data through SQL Server. If an application hits a SQL Server bug
which causes physical corruption, that's still not the application causing physical
corruption, it's SQL Server.
</p>
          <p>
So - on to the myths.
</p>
          <ul>
            <li>
Can an application cause physical corruption? No. 
</li>
            <li>
Can stopping a shrink operation cause corruption of any kind? No. 
</li>
            <li>
Can stopping an index rebuild cause corruption of any kind? No. 
</li>
            <li>
Can running <font face="Courier New">DBCC CHECKDB</font> without repair cause corruption
of any kind? No. 
</li>
            <li>
Can creating a database snapshot cause corruption of any kind? No.</li>
          </ul>
          <p>
Hope this helps.
</p>
        </font>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=6096d901-6322-4328-b62a-dc2b789aa9a5" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>LEGO Olympics</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/27/LEGOOlympics.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,4e023bc6-29cd-46c8-894d-289080c78f77.aspx</id>
    <published>2008-08-27T09:12:00.634-07:00</published>
    <updated>2008-08-27T09:19:32.837125-07:00</updated>
    <category term="Personal" label="Personal" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Personal.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
If you've been following my blog for a while, you'll know that I'm a big fan of LEGO
(see <a class="TitleLinkStyle" href="http://www.sqlskills.com/blogs/paul/2007/10/19/SQLDownUnderPodcastInterviewCHECKDB2008AndWhatDoesPaulGetUpToWhenKimberlysAway.aspx" rel="bookmark"><font color="#696969">SQL
Down Under podcast interview - CHECKDB, 2008, and what does Paul get up to when Kimberly's
away?</font></a>). In fact the kids got me the new <a href="http://shop.lego.com/Product/?p=10187">LEGO
Volkswagen Beetle</a> for my birthday last month - just need the time to make it!
</p>
          <p>
Yesterday, fellow MVP and our good friend <a href="http://blogs.sqlserver.org.au/blogs/Greg_Linwood/">Greg
Linwood</a> set me some pictures of LEGO Olympics. The Hong Kong LEGO User's
Group (can you believe there's a user group for LEGO - that's so cool!) built a complete
miniature set of Beijing Olympic buildings from LEGO. Kimberly found a link to a site
with a bunch of pictures (saves me uploading them here) - check it out at <a href="http://designyoutrust.com/2008/07/29/lego-sports-city-recreates-2008-beijing-olympics/">http://designyoutrust.com/2008/07/29/lego-sports-city-recreates-2008-beijing-olympics/</a><a href="http://www.teamteabag.com:80/2008/08/04/pictures-lego-olympics/"></a>.
Here's one for you - awesome!
</p>
          <p>
            <img src="http://designyoutrust.com/wp-content/uploads3/legob_8.jpg" />
          </p>
        </font>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=4e023bc6-29cd-46c8-894d-289080c78f77" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>Inside the Storage Engine: What's in the buffer pool?</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/26/InsideTheStorageEngineWhatsInTheBufferPool.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,a6ab6c90-a6ed-4463-b3a0-95cf39a2e4c3.aspx</id>
    <published>2008-08-25T18:51:14.665-07:00</published>
    <updated>2008-08-25T18:52:59.009-07:00</updated>
    <category term="Example Scripts" label="Example Scripts" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Example%2BScripts.aspx" />
    <category term="Inside the Storage Engine" label="Inside the Storage Engine" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Inside%2Bthe%2BStorage%2BEngine.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
This is a quick post inspired by a question I was sent in email (thanks Marcos!) which
very neatly lets me show a DMV I've been meaning to blog about for a while. And the
weather here in Redmond really sucks right now so I can't go outside - blogging will
serve as my work-avoidance strategy this afternoon :-).
</p>
          <p>
The (paraphrased) question is:
</p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <p>
              <em>A checkpoint is a process that writes all dirty pages to disk, and is per-database.
So, if the data cache can hold a page from any database, how does checkpoint know
which pages to check for a dirty status? Does it scan through buffer pool looking
for pages for database X and process only those? Or is data cache somehow partitioned
by database? I'd like to know a bit better how it works under the covers.</em>
            </p>
          </blockquote>
          <p dir="ltr">
The answer is that pages are stored in buffers in the buffer pool (aka buffer cache
or data cache), and the buffers are indeed hashed so they can easily be found by database.
You can see what pages are currently in the buffer pool, and their status using
the <font face="Courier New">sys.dm_os_buffer_descriptors</font> DMV in 2005:
</p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <font color="#0000ff" size="5">
              <p>
                <font face="Courier New" size="2">SELECT</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#808080">*</font>
              <font color="#000000">
              </font>
              <font color="#0000ff">FROM</font>
              <font color="#000000">
              </font>
              <font color="#008000">sys.dm_os_buffer_descriptors</font>
            </font>
            <font face="Courier New">
              <font color="#808080">;<br /></font>
              <font size="2">GO</font>
            </font>
            <p>
              <font size="2">
                <font face="Courier New">database_id file_id  page_id  page_level 
allocation_unit_id   page_type      row_count  
free_space_in_bytes is_modified<br />
----------- -------- -------- ----------- -------------------- -------------- -----------
------------------- -----------<br />
1           1       
9        0          
6488064             
BOOT_PAGE      1          
7362               
0<br />
1           1       
6        0          
6488064             
DIFF_MAP_PAGE  2          
6                  
0<br />
1           1       
7        0          
6488064             
ML_MAP_PAGE    2          
6                  
0<br />
1           1       
104      0          
262144              
DATA_PAGE      100        
4196               
0<br />
1           1       
105      0          
851968              
DATA_PAGE      65         
5041               
0<br />
1           1       
106      0          
262144              
DATA_PAGE      197        
413                
0<br />
1           1       
107      0          
262144              
DATA_PAGE      207        
23                 
0<br />
1           1       
108      1          
262144              
INDEX_PAGE     7          
7949               
0<br />
.<br />
.</font>
              </font>
            </p>
          </blockquote>
        </font>
        <p dir="ltr">
I cut off the output rather than list all 3258 pages in the buffer pool on my laptop. The
DMV gives you back some info from the pages themselves as well as you can see(remember
all this is in memory so it's quick to find).
</p>
        <p dir="ltr">
I played around with the DMV a little bit and came up with a neat script that will
tell you may many clean and dirty pages there are in the buffer pool per-database.
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <font color="#0000ff" size="5">
            <p>
              <font face="Courier New" size="2">SELECT<br />
   </font>
            </p>
          </font>
          <font face="Courier New">
            <font color="#808080">(</font>
            <font color="#0000ff">CASE</font>
            <font color="#000000">
            </font>
            <font color="#0000ff">WHEN</font>
            <font color="#000000">
            </font>
            <font color="#808080">(</font>
            <font color="#000000">[is_modified] </font>
            <font color="#808080">=</font>
            <font color="#000000"> 1</font>
            <font color="#808080">) </font>
          </font>
          <font face="Courier New">
            <font color="#0000ff">THEN</font>
            <font color="#ff0000">'Dirty' </font>
          </font>
          <font face="Courier New">
            <font color="#0000ff">ELSE</font>
            <font color="#ff0000">'Clean' </font>
          </font>
          <font face="Courier New">
            <font color="#0000ff">END</font>
            <font color="#808080">)</font>
            <font color="#0000ff">AS</font>
            <font color="#ff0000">'Page
State'</font>
            <font color="#808080">,<br />
   </font>
          </font>
          <font face="Courier New">
            <font color="#808080">(</font>
            <font color="#0000ff">CASE</font>
            <font color="#0000ff">WHEN</font>
            <font color="#808080">(</font>[database_id] <font color="#808080">=</font> 32767<font color="#808080">) </font></font>
          <font face="Courier New">
            <font color="#0000ff">THEN</font>
            <font color="#ff0000">'Resource
Database' </font>
          </font>
          <font face="Courier New">
            <font color="#0000ff">ELSE</font>
            <font color="#ff00ff">DB_NAME</font>
            <font color="#808080">(</font>database_id<font color="#808080">) </font></font>
          <font face="Courier New">
            <font color="#0000ff">END</font>
            <font color="#808080">)</font>
            <font color="#0000ff">AS</font>
            <font color="#ff0000">'Database
Name'</font>
            <font color="#808080">,<br />
   </font>
          </font>
          <font face="Courier New">
            <font color="#ff00ff">COUNT</font>
            <font color="#808080">(*)</font>
            <font color="#0000ff">AS</font>
            <font color="#ff0000">'Page
Count'<br /></font>
          </font>
          <font color="#0000ff">
            <font face="Courier New">FROM</font>
          </font>
          <font face="Courier New">
            <font color="#000000">
            </font>
            <font color="#008000">sys.dm_os_buffer_descriptors<br />
   </font>
          </font>
          <font color="#0000ff">
            <font face="Courier New">GROUP</font>
          </font>
          <font face="Courier New">
            <font color="#000000">
            </font>
            <font color="#0000ff">BY</font>
            <font color="#000000"> [database_id]</font>
            <font color="#808080">,</font>
            <font color="#000000"> [is_modified]<br />
   </font>
          </font>
          <font color="#0000ff">
            <font face="Courier New">ORDER</font>
          </font>
          <font face="Courier New">
            <font color="#000000">
            </font>
            <font color="#0000ff">BY</font>
            <font color="#000000"> [database_id]</font>
            <font color="#808080">,</font>
            <font color="#000000"> [is_modified]</font>
            <font color="#808080">;<br /></font>
          </font>
          <font face="Courier New">GO</font>
          <p>
            <font face="Courier New">Page State Database Name            
Page Count<br />
---------- ------------------------- -----------<br />
Clean      master                   
302<br />
Dirty      master                   
1<br />
Clean      tempdb                   
88<br />
Dirty      tempdb                   
52<br />
Clean      model                    
56<br />
Clean      msdb                     
622<br />
Dirty      msdb                     
5<br />
Clean      adventureworks           
110<br />
Clean      DemoRestoreOrRepair      
64<br />
Clean      DBMaint2008              
88<br />
Clean      DemoFatalCorruption1     
64<br />
Clean      DemoFatalCorruption2     
64<br />
Clean      broken                   
64<br />
Clean      DemoFatalCorruption3     
64<br />
Clean      DemoCorruptMetadata      
111<br />
Clean      DemoDataPurity           
88<br />
Clean      SalesDB                  
123<br />
Clean      DemoNCIndex              
88<br />
Clean      shrinktest               
88<br />
Clean      DemoRestoreOrRepairCopy   64<br />
Clean      DemoSuspect              
64<br />
Clean      FileHeaderTest           
96<br />
Clean      MultiFileDB              
96<br />
Clean      HA2008                   
88<br />
Clean      SalesDB_Snapshot         
21<br />
Clean      BootPageTest             
88<br />
Clean      Resource Database        
599</font>
            <font face="Courier New">
            </font>
          </p>
        </blockquote>
        <p dir="ltr">
Later this week I'll try to blog a script that can tell you how much of a particular
table is in memory. Enjoy!
</p>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=a6ab6c90-a6ed-4463-b3a0-95cf39a2e4c3" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>Should Microsoft provide a transaction log reader tool?</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/26/ShouldMicrosoftProvideATransactionLogReaderTool.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,a3b704d9-7739-43b1-a9eb-7c5e9663eab1.aspx</id>
    <published>2008-08-25T17:21:36.774-07:00</published>
    <updated>2008-08-25T17:22:07.60275-07:00</updated>
    <category term="Database Maintenance" label="Database Maintenance" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Database%2BMaintenance.aspx" />
    <category term="Disaster Recovery" label="Disaster Recovery" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Disaster%2BRecovery.aspx" />
    <category term="Tools" label="Tools" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Tools.aspx" />
    <category term="Transaction Log" label="Transaction Log" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Transaction%2BLog.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
Now this one's sure to spark some controversy...
</p>
          <p>
I was checking my RSS feeds of the SQL blogs that I follow and noticed an interesting
post on Kalen's blog (the post is <a href="http://sqlblog.com/blogs/kalen_delaney/archive/2008/08/23/reading-the-transaction-log.aspx">here</a>).
She'd been lambasted for suggesting in the weekly SQL Server Magazine newsletter that
*Microsoft* shouldn't provide a log reader tool and asked for comments. It's worth
reading her <a href="http://www.sqlmag.com/Articles/Index.cfm?ArticleID=100076">original
newsletter</a> too, as it provides some interesting history of the development of
log readers.
</p>
          <p>
Donning my flame-proof suit, I wholeheartedly agree. I don't think Microsoft should
spend engineering resources on a log reader tool that tries to show the SQL that generated
the log records. So why shouldn't Microsoft build one? Well, IMHO, in a perfect world with
no mistakes and perfect applications, there really isn't a need for a log reader tool.
In an imperfect world, there is a need - but should Microsoft be the one to provide
it? I think there are way more important tools and features that Microsoft should
spend engineering resources on.
</p>
          <p>
So why do people want a log reader tool, apart from curiosity? The three uses I see
are change tracking, auditing, and the ability to rollback mistakes.
</p>
          <p>
The first use, change tracking, is viable, and in fact the change data capture feature
in 2008 is built on top of the transactional replication log reader Agent job (I'll
post more on this, and I've just written an article on tracking changes in 2008 for
the November issue of TechNet Magazine).
</p>
          <p>
For auditing, how can a log reader tell whether the SQL statement was being
run under a different security context, such as after an <font face="Courier New">EXECUTE
AS</font> statement? How can it tell the difference between a single statement <font face="Courier New">UPDATE</font> with
a multi-part <font face="Courier New">WHERE</font> clause, and multiple <font face="Courier New">UPDATE</font> statements
of single rows? And on top of that, it needs to read through all the transaction log,
causing contention on the log drive. In 2008 there's an in-built, synchronous auditing
solution (SQL Server Audit), although it has issues with parameterized queries. In
2005, you could roll your own auditing by having all DML done through stored-procs
that log what they did, for instance, or using DML triggers.
</p>
          <p>
For the ability to rollback mistakes... don't get me started! Recovering from user
mistakes is not a situation you want to be in - you can setup your system to avoid
mistakes altogether. DDL triggers, DML triggers, schema separation, no direct access
to tables for DML, and so on. Any of these are better to do than having to figure
out what someone did so you can undo a mistake. Ok - so people make mistakes and you'd
like to rollback one statement. How about using your backups? Oh, you don't have a
good backup strategy. Well, that's where a log reader can help, if it works. But should
Microsoft have to provide it?
</p>
          <p>
Yes, I know the alternatives I mentioned above are sometimes easier said than
done, especially with 3<sup>rd</sup>-party applications, but that's for the application
writers to fix. Microsoft shouldn't have to provide a tool because of broken applications,
or 3<sup>rd</sup>-party license agreements that preclude adding triggers, or DBAs
that haven't implemented safe-guards. It already provides features that can stop mistakes
happening, and allow auditing to happen. Why provide a log reader tool that allows
other companies to then produce tools on top of that which do what SQL Server already
provides out-of-the-box? And why provide a log reader at all when other companies
do it already?
</p>
          <p>
If anything, I'd like to see the existing tools be made to work in all circumstances.
AFAIK there isn't a log reader tool on the market today that copes with absolutely everything
2005 can put into the log. Although the log internals are supposedly proprietary,
there's an internals document that Microsoft licenses for free (at least when I was
on the team until last summer) to companies wishing to build such tools, and they're
not *secret*. There's plenty of info about the log internals on the web (some provided
by me) and you can poke about to your heart's content using the undocumented tools
(that's what <font face="Courier New">DBCC LOG</font> and <font face="Courier New">fn_dblog</font> are
for).
</p>
          <p>
However, what I'd *really* like to see is the need for a log reader tool to slowly
die away as more devs and DBAs are educated and implement techniques for preventing
the problems that log reader tools help to rectify (sometimes). One thing I haven't
mentioned above is to have a log-shipping secondary with a load-delay - that
way you have a redundant copy of the data that's always several hours behind your
primary system. Or even using regular database snapshots.
</p>
          <p>
Ok - that was a bit of a rant, and this is the same view when I worked for Microsoft
too. To summarize, I don't think Microsoft should provide a log-reader tool.
I see the need for them, when a system isn't setup to prevent mistakes happening,
and there's no good backup or redundancy strategy, but I think that need can be filled
by 3<sup>rd</sup>-party vendors.
</p>
          <p>
Happy to hear well-thought-out arguments on this either way, either privately or as
comments.
</p>
        </font>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=a3b704d9-7739-43b1-a9eb-7c5e9663eab1" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>High-performance FILESTREAM tips and tricks</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/25/HighperformanceFILESTREAMTipsAndTricks.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,37ecf4be-5a41-4990-b055-5d1dc092b7fe.aspx</id>
    <published>2008-08-25T15:53:31.071-07:00</published>
    <updated>2008-08-25T15:54:22.41525-07:00</updated>
    <category term="FILESTREAM" label="FILESTREAM" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,FILESTREAM.aspx" />
    <category term="Performance" label="Performance" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Performance.aspx" />
    <category term="SQL Server 2008" label="SQL Server 2008" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,SQL%2BServer%2B2008.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
Over the last few weeks I've had lots of questions about FILESTREAM performance and
how to coax NTFS into scaling nicely. I just finished writing a 30-page whitepaper
about FILESTREAM for the SQL Server team, which should be published before PASS in
November (I'll blog the link when I have it). Although my whitepaper isn't strictly
about performance, there is a long section about setting up your system to get high-performance
from FILESTREAM. What I want to do in this blog post is give a bullet list of things
to do that will help you get good performance. All of these are explained in more
detail in the whitepaper.
</p>
          <p>
Here you go, in no particular order:
</p>
          <ul>
            <li>
Make sure you're storing the right-sized data in the right way. Jim Gray (et al) published
a research paper a couple of years ago based called <a href="http://research.microsoft.com/research/pubs/view.aspx?msr_tr_id=MSR-TR-2006-45"><em>To
BLOB or Not To BLOB: Large Object Storage in a Database or a Filesystem?</em></a>.
To summarize the findings, BLOBs smaller than 256-KB should be stored in a database,
and 1-MB or larger should be stored in the file-system. For those in-between, "it
depends" - my favorite answer. The upshot of this is that you won't get good performance
if you store lots of small BLOBs in FILESTREAM. 
</li>
            <li>
Use an appropriate RAID level for the NTFS volume that will host the FILESTREAM data
container (the NTFS directory structure corresponding to the FILESTREAM filegroup
in the database). Don't use RAID-5, for instance, for a write-intensive workload. 
</li>
            <li>
Use an appropriate disk technology. SCSI will be usually be faster than SATA/IDE,
but more expensive. This is because SCSI drives usually have higher rotational speeds,
so lower latency and seek times. 
</li>
            <li>
Whichever disk technology you choose, if SATA, ensure it supports NCQ, and if SCSI,
ensure it supports CTQ. Both of these allow the drives to process multiple, interleaved
IOs concurrently. 
</li>
            <li>
Separate the data containers. Separate them from each other, and separate them from
other database data and log files. This avoids contention for the disk heads. 
</li>
            <li>
Defrag the NTFS volume if needed before setting up FILESTREAM, and periodically to
maintain good scan performance 
</li>
            <li>
Turn off 8.3 name generation on the NTFS volume. This is an order-N algorithm that
has to check that the new name generated doesn't collide with any existing names in
the directory. This slows insert and update performance down *a lot*. Do this using
the command line <strong>fsutil</strong> utility. 
</li>
            <li>
Turn off tracking of last access time using fsutil. 
</li>
            <li>
Set the NTFS cluster size appropriately. For BLOBs 1-MB or large, use a cluster size
of 64-KB. This will help to reduce fragmentation. 
</li>
            <li>
A partial update of FILESTREAM data creates a new file. Batch lots of small updates
into one large update to reduce churn. 
</li>
            <li>
When streaming the data back to the client, use an ~60-KB SMB buffer size (or multiples
thereof). This is so that the buffers don't get overly fragmented as TCP/IP buffer
are 64-KB.</li>
          </ul>
          <p>
Hope this helps!
</p>
        </font>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=37ecf4be-5a41-4990-b055-5d1dc092b7fe" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>Search Engine Q&amp;A #25: Why isn't my log backup the same size as my log?</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/25/SearchEngineQA25WhyIsntMyLogBackupTheSameSizeAsMyLog.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,bb4872b5-6e21-4627-9fc6-57aa1e63d990.aspx</id>
    <published>2008-08-24T17:23:47.052-07:00</published>
    <updated>2008-08-24T17:28:43.2112435-07:00</updated>
    <category term="Backup/Restore" label="Backup/Restore" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Backup%2fRestore.aspx" />
    <category term="Database Maintenance" label="Database Maintenance" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Database%2BMaintenance.aspx" />
    <category term="Example Scripts" label="Example Scripts" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Example%2BScripts.aspx" />
    <category term="Search Engine Q and A" label="Search Engine Q and A" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Search%2BEngine%2BQ%2Band%2BA.aspx" />
    <category term="Transaction Log" label="Transaction Log" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Transaction%2BLog.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
I woke up this morning and someone had replaced my wife with someone who likes to
blog :-). Kimberly's turned over a new leaf and is going to blog much more often
- in fact she's blogged 4 times today already. Check out her blog <a href="http://www.sqlskills.com/blogs/kimberly">here</a>.
</p>
          <p>
Continuing on the transaction log theme of the last few Search Engine Q&amp;A posts,
this one addresses a question I've heard a few times, most recently on an MVP discussion
group. Let me paraphrase:
</p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <p>
If I have a transaction that inserts a huge amount of data, the transaction log grows
to 50-GB. I then rollback the transaction. When I take the next log backup, it's way
smaller than 50-GB. What's going on?
</p>
          </blockquote>
          <p dir="ltr">
Let's see if we can repro the scenario. I've created a database with a 500-MB data
file and a 1-MB log file, with 100-MB and 1-MB auto-growth intervals. I want the log
to be as small as possible and to grow in small chunks so I can see just how much
it *has* to grow by, rather than having a large growth size. Then I set the recovery
mode to full and took a database backup to make sure the log won't truncate until
it's backed up.
</p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <font color="#0000ff" size="5">
              <p>
                <font face="Courier New" size="2">CREATE</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DATABASE</font>
              <font color="#000000"> LogSizeTest </font>
              <font color="#0000ff">ON<br />
   </font>
            </font>
            <font face="Courier New">
              <font color="#808080">(</font>
              <font color="#0000ff">NAME</font>
              <font color="#808080">=</font> N<font color="#ff0000">'LogSizeTest'</font><font color="#808080">,<br />
   </font></font>
            <font face="Courier New">
              <font color="#0000ff">FILENAME</font>
              <font color="#808080">=</font> N<font color="#ff0000">'C:\SQLskills\LogSizeTest.mdf'</font><font color="#808080">,<br />
   </font></font>
            <font face="Courier New">
              <font color="#0000ff">SIZE</font>
              <font color="#808080">=</font> 512MB<font color="#808080">,<br />
   </font></font>
            <font face="Courier New">
              <font color="#0000ff">FILEGROWTH</font>
              <font color="#808080">=</font> 100MB<font color="#808080">)<br /></font></font>
            <font face="Courier New">
              <font color="#ff00ff">LOG</font>
              <font color="#0000ff">ON</font> <br />
   </font>
            <font face="Courier New">
              <font color="#808080">(</font>
              <font color="#0000ff">NAME</font>
              <font color="#808080">=</font> N<font color="#ff0000">'LogSizeTest_log'</font><font color="#808080">,<br />
   </font></font>
            <font face="Courier New">
              <font color="#0000ff">FILENAME</font>
              <font color="#808080">=</font> N<font color="#ff0000">'C:\SQLskills\LogSizeTest_log.ldf'</font><font color="#808080">,<br /></font></font>
            <font face="Courier New">
              <font color="#0000ff">   SIZE</font>
              <font color="#808080">=</font> 1MB<font color="#808080">,<br />
   </font><font color="#0000ff">FILEGROWTH</font><font color="#808080">=</font> 1MB<font color="#808080">);<br /></font></font>
            <font face="Courier New">GO</font>
            <font color="#0000ff">
              <p>
                <font face="Courier New">ALTER</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DATABASE</font>
              <font color="#000000"> LogSizeTest </font>
              <font color="#0000ff">SET</font>
              <font color="#000000">
              </font>
              <font color="#0000ff">RECOVERY</font>
              <font color="#000000">
              </font>
              <font color="#0000ff">FULL</font>
              <font color="#808080">;<br /></font>
            </font>
            <font face="Courier New">GO</font>
            <font color="#0000ff">
              <p>
                <font face="Courier New">BACKUP</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DATABASE</font>
              <font color="#000000"> LogSizeTest </font>
              <font color="#0000ff">TO</font>
              <font color="#000000">
              </font>
              <font color="#0000ff">DISK</font>
              <font color="#000000">
              </font>
              <font color="#808080">=</font>
              <font color="#000000">
              </font>
              <font color="#ff0000">'C:\SQLskills\LogSizeTest.bak'</font>
              <font color="#808080">;<br /></font>
            </font>
            <font face="Courier New" size="2">GO</font>
          </blockquote>
          <p dir="ltr">
            <font face="Courier New" size="2">
              <font face="Verdana">Let's check the size of the
log:</font>
            </font>
          </p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <font face="Courier New" size="2">
              <font face="Verdana">
                <font color="#0000ff" size="5">
                  <p>
                    <font face="Courier New" size="2">DBCC</font>
                  </p>
                </font>
                <font face="Courier New">
                  <font color="#000000"> SQLPERF </font>
                  <font color="#808080">(</font>
                  <font color="#000000">LOGSPACE</font>
                  <font color="#808080">);<br /></font>
                </font>
                <font face="Courier New" size="2">GO</font>
                <p>
                  <font face="Courier New" size="2">Database Name  Log Size (MB) Log Space Used
(%) Status<br />
-------------- ------------- ------------------ -----------<br />
LogSizeTest    0.9921875     36.66339          
0<br /></font>
                </p>
              </font>
            </font>
          </blockquote>
        </font>
        <p dir="ltr">
          <font face="Courier New" size="2">
            <font face="Verdana">This gives back info for all
databases, I've trimmed down the output just for the <font face="Courier New">LogSizeTest</font> database.</font>
          </font>
        </p>
        <p dir="ltr">
          <font face="Courier New" size="2">
            <font face="Verdana">Now I'm going to create a table,
start an explicit transaction and add about 500-MB of info to the table.</font>
          </font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <font face="Courier New" size="2">
            <font face="Verdana">
              <font color="#0000ff" size="5">
                <p>
                  <font face="Courier New" size="2">USE</font>
                </p>
              </font>
              <font face="Courier New">
                <font color="#000000"> LogSizeTest</font>
                <font color="#808080">;<br /></font>
              </font>
              <font face="Courier New">GO<br /></font>
              <font color="#0000ff">
                <font color="#0000ff" size="5">
                  <font face="Courier New" size="2">SET</font>
                </font>
                <font face="Courier New">
                  <font color="#000000">
                  </font>
                  <font color="#0000ff">NOCOUNT</font>
                  <font color="#000000">
                  </font>
                  <font color="#0000ff">ON</font>
                  <font color="#808080">;<br /></font>
                </font>
                <font size="5">
                  <font face="Courier New" color="#000000" size="2">GO<br /></font>
                </font>
                <font face="Courier New">CREATE</font>
              </font>
              <font face="Courier New">
                <font color="#000000">
                </font>
                <font color="#0000ff">TABLE</font>
                <font color="#000000"> Test </font>
                <font color="#808080">(</font>
              </font>
              <font face="Courier New">c1 </font>
              <font face="Courier New">
                <font color="#0000ff">INT</font>
                <font color="#0000ff">IDENTITY</font>
                <font color="#808080">, </font>
              </font>
              <font face="Courier New">C2 </font>
              <font face="Courier New">
                <font color="#0000ff">CHAR</font>
                <font color="#808080">(</font>8000<font color="#808080">)</font><font color="#0000ff">DEFAULT</font><font color="#808080">(</font><font color="#ff00ff">REPLICATE</font><font color="#808080">(</font><font color="#ff0000">'a'</font><font color="#808080">,</font> 8000<font color="#808080">)));<br /></font></font>
              <font face="Courier New">GO
</font>
              <font color="#0000ff">
                <p>
                  <font face="Courier New">BEGIN</font>
                </p>
              </font>
              <font face="Courier New">
                <font color="#000000">
                </font>
                <font color="#0000ff">TRAN</font>
                <font color="#808080">;<br /></font>
              </font>
              <font face="Courier New">GO
</font>
              <font color="#0000ff">
                <p>
                  <font face="Courier New">DECLARE</font>
                </p>
              </font>
              <font face="Courier New">
                <font color="#000000"> @count </font>
                <font color="#0000ff">INT</font>
                <font color="#808080">;<br /></font>
              </font>
              <font color="#0000ff">
                <font face="Courier New">SELECT</font>
              </font>
              <font face="Courier New">
                <font color="#000000"> @count </font>
                <font color="#808080">=</font>
                <font color="#000000"> 0</font>
                <font color="#808080">;<br /></font>
              </font>
              <font color="#0000ff">
                <font face="Courier New">WHILE</font>
              </font>
              <font face="Courier New">
                <font color="#000000">
                </font>
                <font color="#808080">(</font>
                <font color="#000000">@count </font>
                <font color="#808080">&lt;</font>
                <font color="#000000"> 64000</font>
                <font color="#808080">)<br /></font>
              </font>
              <font face="Courier New" color="#0000ff">BEGIN<br />
   </font>
              <font face="Courier New">
                <font color="#0000ff">INSERT</font>
                <font color="#0000ff">INTO</font> Test <font color="#0000ff">DEFAULT</font><font color="#0000ff">VALUES</font><font color="#808080">;<br />
   </font></font>
              <font face="Courier New">
                <font color="#0000ff">SELECT</font> @count <font color="#808080">=</font> @count <font color="#808080">+</font> 1<font color="#808080">;<br /></font></font>
              <font color="#0000ff">
                <font face="Courier New">END</font>
              </font>
              <font color="#808080">
                <font face="Courier New">;<br /></font>
              </font>
              <font face="Courier New" size="2">GO
</font>
            </font>
          </font>
        </blockquote>
        <p dir="ltr">
          <font face="Courier New" size="2">
            <font face="Verdana">Checking the log file size
again gives:</font>
          </font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <font face="Courier New" size="2">
            <font color="#0000ff" size="5">
              <p>
                <font size="2">DBCC</font>
              </p>
            </font>
            <font color="#000000"> SQLPERF </font>
            <font color="#808080">(</font>
            <font color="#000000">LOGSPACE</font>
            <font color="#808080">);<br /></font>
            <font size="5">
              <font size="2">GO</font>
              <p dir="ltr">
              </p>
            </font>Database Name  Log Size (MB) Log Space Used (%) Status<br />
-------------- ------------- ------------------ -----------<br />
LogSizeTest    703.9922      99.98737          
0</font>
        </blockquote>
        <p dir="ltr">
          <font face="Courier New" size="2">
            <font face="Verdana">The log size has grown to about
700-MB, way more than the size of the data I was inserting, and it's completely full.
Now let's rollback the transaction and check the log size again.</font>
          </font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <font face="Courier New" size="2">
            <font face="Verdana">
              <font color="#0000ff" size="5">
                <p>
                  <font face="Courier New" size="2">ROLLBACK</font>
                </p>
              </font>
              <font face="Courier New">
                <font color="#000000">
                </font>
                <font color="#0000ff">TRAN</font>
              </font>
              <font face="Courier New">
                <font color="#808080">;<br /></font>GO</font>
              <font color="#0000ff">
                <p>
                  <font face="Courier New">DBCC</font>
                </p>
              </font>
              <font face="Courier New">
                <font color="#000000"> SQLPERF </font>
                <font color="#808080">(</font>
                <font color="#000000">LOGSPACE</font>
              </font>
              <font face="Courier New">
                <font color="#808080">);<br /></font>
                <font size="2">GO</font>
              </font>
              <p>
                <font size="2">
                  <font face="Courier New">Database Name  Log Size (MB) Log Space
Used (%) Status<br />
-------------- ------------- ------------------ -----------<br />
LogSizeTest    703.9922      85.21268          
0</font>
                </font>
              </p>
            </font>
          </font>
        </blockquote>
        <p dir="ltr">
          <font face="Courier New" size="2">
            <font face="Verdana">The size of the log file is
the same, but the percentage used has actually gone down! How can that happen? Let's
take a backup and checkout it's size:</font>
          </font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <font face="Courier New" size="2">
            <font face="Verdana">
              <font color="#0000ff" size="5">
                <p>
                  <font face="Courier New" size="2">BACKUP</font>
                </p>
              </font>
              <font face="Courier New">
                <font color="#000000">
                </font>
                <font color="#ff00ff">LOG</font>
                <font color="#000000"> LogSizeTest </font>
                <font color="#0000ff">TO</font>
                <font color="#000000">
                </font>
                <font color="#0000ff">DISK</font>
                <font color="#000000">
                </font>
                <font color="#808080">=</font>
                <font color="#000000">
                </font>
                <font color="#ff0000">'C:\SQLskills\LogSizeTest_log.bck'</font>
                <font color="#808080">;<br /></font>
              </font>
              <font face="Courier New">GO<br /></font>
              <font color="#0000ff">
                <font face="Courier New">RESTORE</font>
              </font>
              <font face="Courier New">
                <font color="#000000">
                </font>
                <font color="#0000ff">HEADERONLY</font>
                <font color="#000000">
                </font>
                <font color="#0000ff">FROM</font>
                <font color="#000000">
                </font>
                <font color="#0000ff">DISK</font>
                <font color="#000000">
                </font>
                <font color="#808080">=</font>
                <font color="#000000">
                </font>
                <font color="#ff0000">'C:\SQLskills\LogSizeTest_log.bck'</font>
                <font color="#808080">;<br /></font>
              </font>
              <font face="Courier New">GO</font>
            </font>
          </font>
        </blockquote>
        <p>
The <font face="Courier New">BackupSize</font> in the output from the <font face="Courier New">RESTORE
HEADERONLY</font> is 631454208, which is 602.2-MB. Taking the numbers from the <font face="Courier New">DBCC
SQLPER</font>F output above, 85.21268% of 703.9922-MB is 599.89-MB - so the backup
is roughly the same size as the used transaction log. That's what I'd expect, but
why is it smaller than the total size of the transaction log?
</p>
        <p>
So what's going on? Why did the transaction log need to grow so much larger than it
needed to, and why did the percentage used actually *drop* after the transaction rolled
back?
</p>
        <p>
The answer is in the way the transaction log works. Whenever a logged operation occurs
in a transaction, there is some transaction log space <em>reserved</em> in case the
transaction rolls back. The idea is that there's always enough space available in
the transaction log for a transaction to roll back, without having to grow the transaction
log and potentially have that fail. If a transaction could not roll back successfully
because the log didn't have enough space, the database would become transactionally
inconsistent, would be taken offline and the state changed to <font face="Courier New">SUSPECT</font>.
</p>
        <p>
The behavior we saw was the Storage Engine reserving transaction log space for a potential
roll back. When the roll back occured, the transaction log records necessary to undo
the effects of the transaction (called <em>compensation log records</em>) are created
and written to the log. The issue is that they usually don't take up as much space
as the Storage Engine reserved, as it tends to be very conservative in its estimates
of how much log space to reserve, to avoid the potential for <font face="Courier New">SUSPECT</font> databases.
This explains the difference between the various sizes and percentages we saw above.
</p>
        <p>
The Storage Engine code to do the reservations is quite interesting - I remember
fixing a couple of bugs in it during SQL Server 2000 development in 1999 while I was
getting to know the internals of the logging and recovery system before tackling some
of the (since removed) log-reading code in DBCC CHECKDB in SQL Server 2000.
</p>
        <p>
Anyway, there you have it. Log space reservation is the answer, and is also one of
the reasons why it can be tricky to estimate how large a transaction log should be
when a database is created.
</p>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=bb4872b5-6e21-4627-9fc6-57aa1e63d990" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>SQL Server 2008: Does my database contain Enterprise-only features?</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/23/SQLServer2008DoesMyDatabaseContainEnterpriseonlyFeatures.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,58403e96-df8f-457c-8114-1ded39df724c.aspx</id>
    <published>2008-08-23T09:06:18.168-07:00</published>
    <updated>2008-08-23T09:10:15.8245-07:00</updated>
    <category term="Backup/Restore" label="Backup/Restore" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Backup%2fRestore.aspx" />
    <category term="Change Data Capture" label="Change Data Capture" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Change%2BData%2BCapture.aspx" />
    <category term="Compression" label="Compression" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Compression.aspx" />
    <category term="Database Maintenance" label="Database Maintenance" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Database%2BMaintenance.aspx" />
    <category term="Disaster Recovery" label="Disaster Recovery" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Disaster%2BRecovery.aspx" />
    <category term="Encryption" label="Encryption" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Encryption.aspx" />
    <category term="Partitioning" label="Partitioning" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Partitioning.aspx" />
    <category term="Security" label="Security" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Security.aspx" />
    <category term="SQL Server 2008" label="SQL Server 2008" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,SQL%2BServer%2B2008.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
Moving databases around is pretty common, as is moving databases between servers running
different Editions of SQL Server, especially during a disaster recovery situation.
You may not know this, but in SQL Server 2005, if you had partitioning anywhere in
a database, you could only attach/restore that database using an Enterprise or Developer
instance. I say 'you may not know this' because partitioning isn't really widely used
(from what I can gather from talking to customers). The upshot of this is that SQL
Server 2005 will refuse to attach/restore a database with partitioning in - even if
you're in a disaster recovery situation and the only server you have available has
Standard Edition.
</p>
          <p>
In SQL Server 2008, a lot more people are going to bump into this issue. The list
of features that are Enterprise only, and will prevent attach/restore using a lower
edition has expanded to include 3 new features that WILL be much more commonly used
than partitioning. The four features that are in this category are:
</p>
          <ul>
            <li>
Data compression 
</li>
            <li>
Partitioning 
</li>
            <li>
Transparent data encryption 
</li>
            <li>
Change data capture</li>
          </ul>
          <p>
All of these require elevated permissions to enable EXCEPT data compression, which
only requires ALTER permission on a table. This means someone with table-owner privileges
could enable compression without the DBA knowing, and suddenly the database can't
be attached/restored to, say, Standard Edition.
</p>
          <p>
If you're a DBA and have just taken over a database, there's now an easy way to tell
whether the database contains these features. A new DMV has been added - <em>sys.dm_db_persisted_sku_features</em> -
that will report which of these four features are present in a database. Let's check
it out.
</p>
          <p>
Using a 2008 Enterprise instance:
</p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <font color="#0000ff" size="5">
              <p>
                <font face="Courier New" size="2">CREATE</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DATABASE</font>
              <font color="#000000"> EnterpriseOnly</font>
              <font color="#808080">;<br /></font>
            </font>
            <font face="Courier New" color="#0000ff">GO<br /></font>
            <font color="#0000ff">
              <font face="Courier New">USE</font>
            </font>
            <font face="Courier New">
              <font color="#000000"> EnterpriseOnly</font>
              <font color="#808080">;<br /></font>
            </font>
            <font face="Courier New">
              <font color="#0000ff">GO</font>
            </font>
            <font color="#0000ff">
              <p>
                <font face="Courier New">CREATE</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">TABLE</font>
              <font color="#000000"> compressed </font>
              <font color="#808080">(</font>
              <font color="#000000">c1 </font>
              <font color="#0000ff">INT</font>
              <font color="#808080">) </font>
            </font>
            <font color="#0000ff">
              <font face="Courier New">WITH</font>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#808080">(</font>
              <font color="#000000">DATA_COMPRESSION </font>
              <font color="#808080">=</font>
              <font color="#000000"> ROW</font>
              <font color="#808080">);<br /></font>
            </font>
            <font face="Courier New">
              <font color="#0000ff">GO</font>
            </font>
            <font color="#0000ff">
              <p>
                <font face="Courier New">SELECT</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#808080">*</font>
              <font color="#000000">
              </font>
              <font color="#0000ff">FROM</font>
              <font color="#000000">
              </font>
              <font color="#008000">sys.dm_db_persisted_sku_features</font>
              <font color="#808080">;<br /></font>
            </font>
            <font face="Courier New" color="#0000ff">GO</font>
            <p>
              <font face="Courier New" color="#000000">feature_name    feature_id<br />
--------------  -----------<br />
Compression     100</font>
            </p>
          </blockquote>
          <p dir="ltr">
Now let's try backing up and restoring the database on a different edition:
</p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <font color="#0000ff" size="5">
              <p>
                <font face="Courier New" size="2">BACKUP</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DATABASE</font>
              <font color="#000000"> EnterpriseOnly </font>
            </font>
            <font color="#0000ff">
              <font face="Courier New">TO</font>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DISK</font>
              <font color="#000000">
              </font>
              <font color="#808080">=</font>
              <font color="#000000">
              </font>
              <font color="#ff0000">'C:\SQLskills\EnterpriseOnly.bck'</font>
              <font color="#808080">;<br /></font>
            </font>
            <font face="Courier New" color="#0000ff">GO</font>
          </blockquote>
          <p dir="ltr">
And on a 2008 Express instance:
</p>
          <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
            <font color="#0000ff" size="5">
              <p>
                <font face="Courier New" size="2">RESTORE</font>
              </p>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DATABASE</font>
              <font color="#000000"> EnterpriseOnly </font>
            </font>
            <font color="#0000ff">
              <font face="Courier New">FROM</font>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">DISK</font>
              <font color="#000000">
              </font>
              <font color="#808080">=</font>
              <font color="#000000">
              </font>
              <font color="#ff0000">'C:\SQLskills\EnterpriseOnly.bck'<br />
   </font>
            </font>
            <font color="#0000ff">
              <font face="Courier New">WITH</font>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#0000ff">MOVE</font>
              <font color="#000000">
              </font>
              <font color="#ff0000">'EnterpriseOnly'</font>
              <font color="#000000">
              </font>
              <font color="#0000ff">TO</font>
              <font color="#000000">
              </font>
              <font color="#ff0000">'C:\SQLskills\EnterpriseOnly.mdf'</font>
              <font color="#808080">,<br />
   </font>
            </font>
            <font color="#0000ff">
              <font face="Courier New">MOVE</font>
            </font>
            <font face="Courier New">
              <font color="#000000">
              </font>
              <font color="#ff0000">'EnterpriseOnly_log'</font>
              <font color="#000000">
              </font>
              <font color="#0000ff">TO</font>
              <font color="#000000">
              </font>
              <font color="#ff0000">'C:\SQLskills\EnterpriseOnly_log.ldf'<br /></font>
            </font>
            <font face="Courier New" size="2">
              <font color="#0000ff">GO</font>
            </font>
            <p>
              <font face="Courier New" size="2">Processed 160 pages for database 'EnterpriseOnly',
file 'EnterpriseOnly' on file 1.<br />
Processed 5 pages for database 'EnterpriseOnly', file 'EnterpriseOnly_log' on file
1.<br /><font color="#ff0000">Msg 3167, Level 16, State 1, Line 1<br />
RESTORE could not start database 'EnterpriseOnly'.<br />
Msg 3013, Level 16, State 1, Line 1<br />
RESTORE DATABASE is terminating abnormally.<br />
Msg 909, Level 21, State 1, Line 1<br />
Database 'EnterpriseOnly' cannot be started in this edition of SQL Server because
part or all of object 'compressed' is enabled with data compression or vardecimal
storage format. Data compression and vardecimal storage format are only supported
on SQL Server Enterprise Edition.<br />
Msg 933, Level 21, State 1, Line 1<br />
Database 'EnterpriseOnly' cannot be started because some of the database functionality
is not available in the current edition of SQL Server.<br /></font></font>
            </p>
          </blockquote>
        </font>
        <p dir="ltr">
Now, it's cool that it tells you exactly why the database couldn't be restored, but
did you notice the first two lines of output? The database is fully restored BEFORE
the operation fails! This makes perfect sense, as the database needs to be fully recovered
before the server can tell whether any of the four features are still enabled or not.
However, in a disaster recovery situation, waiting many hours for a database to restore
only to be told that it can't be restored on this instance would be even more disastrous.
</p>
        <p dir="ltr">
To summarize, you should always know what's happening in databases you manage. If
portability of your databases to a lower Edition is important, make sure that none
of these features can be enabled without you knowing about it.
</p>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=58403e96-df8f-457c-8114-1ded39df724c" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
  <entry>
    <title>Weird Boeing test flight</title>
    <link rel="alternate" type="text/html" href="http://www.sqlskills.com/blogs/paul/2008/08/22/WeirdBoeingTestFlight.aspx" />
    <id>http://www.sqlskills.com/blogs/paul/PermaLink,guid,ca9a0cfb-041f-472a-abab-4bd1b8f02da1.aspx</id>
    <published>2008-08-22T12:06:25.8245-07:00</published>
    <updated>2008-08-22T12:06:25.8245-07:00</updated>
    <category term="Personal" label="Personal" scheme="http://www.sqlskills.com/blogs/paul/CategoryView,category,Personal.aspx" />
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <font face="Verdana" size="2">
          <p>
Just a bit off-topic on this one!
</p>
          <p>
I was sitting working on our top deck this morning when I spotted a large commerical
airliner being shadowed by a small jet. I rushed in to grab my binoculars, assuming
the escort was military and something was wrong with the airliner. Then things got
really weird - the airliner started losing height, then climbing sharply, doing circles
and sharp turns - all the while with the smaller jet buzzing around it. I was surprised
with some of the manouvers the airliner was making, it seemed to go really low at
times.
</p>
          <p>
Here's where I started to get more excited - our top deck looks out over Lake
Sammamish, with a 180<sup>o</sup> view of the Cascades from North Bend up to Mount
Baker, so I could watch the jets all the time. This is about 20 miles south of the
Boeing plant at Everett, WA which is assembling the 787 Dreamliner. Could it
be an early, unannounced test flight? The jets finally came close enough to identify
the livery as Emirates Airlines. However, checking the Wikipedia list of 787 orders
(see <a href="http://en.wikipedia.org/wiki/List_of_Boeing_787_orders">http://en.wikipedia.org/wiki/List_of_Boeing_787_orders</a>),
I don't see them listed, and IIRC they've bought a bunch of Airbus A380s.
</p>
          <p>
So, I was dismayed to start with thinking I was watching a hijacking in progress,
then excited for a bit thinking I was watching an unannounced test flight, but it
must have been for a 777 instead. Still, very strange to see a little jet buzzing
around a very large one, and to see the large one doing such dramatic manouvers so
close the ground. Wish I'd thought to take a photo of them.
</p>
          <p>
Oh well, back to work...
</p>
        </font>
        <img width="0" height="0" src="http://www.sqlskills.com/blogs/paul/aggbug.ashx?id=ca9a0cfb-041f-472a-abab-4bd1b8f02da1" />
        <br />
        <hr />
This weblog is sponsored by <a href="http://www.SQLskills.com">SQLskills.com</a>.
(c) Paul S. Randal. This feed is for personal, non-commercial use.
</div>
    </content>
  </entry>
</feed>