<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tags 'log' and 'T-SQL Tuesday'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=log,T-SQL+Tuesday&amp;orTags=0</link><description>Search results matching tags 'log' and 'T-SQL Tuesday'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>T-SQL Tuesday #31: Paradox of the Sawtooth Log</title><link>http://sqlblog.com/blogs/merrill_aldrich/archive/2012/06/12/t-sql-tuesday-31-paradox-of-the-sawtooth-log.aspx</link><pubDate>Tue, 12 Jun 2012 07:10:29 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:43843</guid><dc:creator>merrillaldrich</dc:creator><description>&lt;p&gt;&lt;a href="http://sqlvariant.com/2012/06/t-sql-tuesday-31-logging/"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" title="TSQL2sDay150x150_thumb" border="0" alt="TSQL2sDay150x150_thumb" src="http://sqlblog.com/blogs/merrill_aldrich/TSQL2sDay150x150_thumb_779A8EA5.jpg" width="154" height="154" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Today’s T-SQL Tuesday, hosted by Aaron Nelson (&lt;a href="http://twitter.com/#!/sqlvariant"&gt;@sqlvariant&lt;/a&gt; | &lt;a href="http://sqlvariant.com/2012/06/t-sql-tuesday-31-logging/"&gt;sqlvariant.com&lt;/a&gt;) has the theme &lt;em&gt;Logging&lt;/em&gt;. I was a little pressed for time today to pull this post together, so this will be short and sweet. For a long time, I wondered why and how a database in Full Recovery Mode, which you’d expect to have an ever-growing log -- as all changes are written to the log file -- could in fact have a log usage pattern that looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/merrill_aldrich/SawToothLogUsage_48D4D603.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" title="SawToothLogUsage" border="0" alt="SawToothLogUsage" src="http://sqlblog.com/blogs/merrill_aldrich/SawToothLogUsage_thumb_35B3A957.png" width="792" height="539" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This graph shows the &lt;strong&gt;Percent Log Used&lt;/strong&gt; (bold, red) and the &lt;strong&gt;Log File(s) Used Size KB&lt;/strong&gt; (light, green) counters for a demo database. The database was in Full Recovery mode the whole time this graph was generated, and there were no log backups taken. It seems, naively, that the graph should just climb ever upward as changes are added. How could it possibly drop and then start to climb again? Mysterious.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;gt;&amp;gt; If I had time and wit, this is where I would do some clever Scooby Doo or Nancy Drew thing. Not tonight, I’m afraid. &amp;lt;&amp;lt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I learned the answer in an amazing session with &lt;a href="http://sqlskills.com"&gt;SQL Skills&lt;/a&gt;, during their IE1 class. The answer is that the amount of space counted as “used” in the log includes the log records physically present in the log file and in use (for full recovery, mirroring, replication, etc.) &lt;em&gt;plus&lt;/em&gt; the amount of space that would be required to &lt;em&gt;add&lt;/em&gt; rollback records, which do not actually exist, for all inflight transactions.&lt;/p&gt;  &lt;p&gt;When you make a change to a database, the change is recorded first, obviously, as a series of transaction log records that can be played forward. In the event of a crash, when recovery runs, those records are replayed forward to recreate the changes, as one stage of the recovery process. But if a transaction is incomplete, somehow the instructions need to be present to undo and reverse out the changes made in that transaction. The way that works is that at the time of rollback, the reverse operations from the original log records are added to the log, then those reversal records are &lt;em&gt;also&lt;/em&gt; played forward, which “undoes” all the changes. The reversal records do not exist, though, unless a rollback is actually invoked.&lt;/p&gt;  &lt;p&gt;If the server ran out of space in the log file to append these rollback records, obviously there would be a major problem, and we might not be able to recover the database. In order to prevent that condition, SQL Server will reserve the space necessary in the log file(s) and have it appear “used” until a given transaction commits, at which point the crash recovery space for these hypothetical reversal records is no longer a requirement.&lt;/p&gt;  &lt;p&gt;Here’s a demo script if you want to see this in action. Note that it takes a fair amount of disk space:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;USE master &lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

&lt;/span&gt;&lt;span style="color:green;"&gt;-- Make a demo database:

&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE DATABASE &lt;/span&gt;LogDemo &lt;span style="color:gray;"&gt;;
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

ALTER DATABASE &lt;/span&gt;LogDemo &lt;span style="color:blue;"&gt;SET RECOVERY FULL &lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

ALTER DATABASE &lt;/span&gt;LogDemo 
     &lt;span style="color:blue;"&gt;MODIFY FILE &lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;NAME &lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:red;"&gt;N'LogDemo'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;SIZE &lt;span style="color:gray;"&gt;= &lt;/span&gt;2000MB &lt;span style="color:gray;"&gt;, &lt;/span&gt;FILEGROWTH &lt;span style="color:gray;"&gt;= &lt;/span&gt;0&lt;span style="color:gray;"&gt;)
&lt;/span&gt;&lt;span style="color:blue;"&gt;ALTER DATABASE &lt;/span&gt;LogDemo 
     &lt;span style="color:blue;"&gt;MODIFY FILE &lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;NAME &lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:red;"&gt;N'LogDemo_log'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;SIZE &lt;span style="color:gray;"&gt;= &lt;/span&gt;2000MB &lt;span style="color:gray;"&gt;, &lt;/span&gt;FILEGROWTH &lt;span style="color:gray;"&gt;= &lt;/span&gt;0&lt;span style="color:gray;"&gt;)
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

USE &lt;/span&gt;LogDemo
&lt;span style="color:blue;"&gt;GO

CREATE TABLE &lt;/span&gt;DummyData &lt;span style="color:gray;"&gt;( &lt;/span&gt;Padding &lt;span style="color:blue;"&gt;char&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;800&lt;span style="color:gray;"&gt;) ) ;
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

&lt;/span&gt;&lt;span style="color:green;"&gt;-- Init full recovery mode by taking a full backup:

&lt;/span&gt;&lt;span style="color:blue;"&gt;BACKUP DATABASE &lt;/span&gt;LogDemo &lt;span style="color:blue;"&gt;TO DISK &lt;/span&gt;&lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:red;"&gt;'LogDemo.BAK'
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

&lt;/span&gt;&lt;span style="color:green;"&gt;-- At this point, start Performance Monitor, and add the counters
-- Percent Log Used and Log File(s) Size Used (KB) for the demo DB
-- Set the display scale of the latter to 0.00001 to match
-- the screenshot

-- Fill the test table with a generous amount of data:

&lt;/span&gt;&lt;span style="color:blue;"&gt;DECLARE &lt;/span&gt;@i &lt;span style="color:blue;"&gt;int &lt;/span&gt;&lt;span style="color:gray;"&gt;= &lt;/span&gt;1 &lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;-- You can experiment with how much data by adjusting this
-- limit:

&lt;/span&gt;&lt;span style="color:blue;"&gt;WHILE &lt;/span&gt;@i &lt;span style="color:gray;"&gt;&amp;lt; &lt;/span&gt;2 &lt;span style="color:blue;"&gt;BEGIN

    BEGIN TRANSACTION &lt;/span&gt;&lt;span style="color:gray;"&gt;;

    &lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:03' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

    &lt;/span&gt;&lt;span style="color:green;"&gt;-- With each iteration of this loop, the log use will ramp up
    -- in the &amp;quot;intuitive&amp;quot; way we expect, growing after each insert:
    
    &lt;/span&gt;&lt;span style="color:blue;"&gt;WITH  
        &lt;/span&gt;t1 &lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color:magenta;"&gt;REPLICATE&lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:red;"&gt;'x'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;800 &lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;Padding 
                &lt;span style="color:blue;"&gt;UNION &lt;/span&gt;&lt;span style="color:gray;"&gt;ALL &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color:magenta;"&gt;REPLICATE&lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:red;"&gt;'x'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;800 &lt;span style="color:gray;"&gt;) &lt;/span&gt;&lt;span style="color:blue;"&gt;AS &lt;/span&gt;Padding &lt;span style="color:gray;"&gt;),
        &lt;/span&gt;t2 &lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;x&lt;span style="color:gray;"&gt;.&lt;/span&gt;Padding &lt;span style="color:blue;"&gt;FROM &lt;/span&gt;t1 x &lt;span style="color:gray;"&gt;CROSS JOIN &lt;/span&gt;t1 y &lt;span style="color:gray;"&gt;),
        &lt;/span&gt;t3 &lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;x&lt;span style="color:gray;"&gt;.&lt;/span&gt;Padding &lt;span style="color:blue;"&gt;FROM &lt;/span&gt;t2 x &lt;span style="color:gray;"&gt;CROSS JOIN &lt;/span&gt;t2 y &lt;span style="color:gray;"&gt;),
        &lt;/span&gt;t4 &lt;span style="color:blue;"&gt;AS &lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;x&lt;span style="color:gray;"&gt;.&lt;/span&gt;Padding &lt;span style="color:blue;"&gt;FROM &lt;/span&gt;t3 x &lt;span style="color:gray;"&gt;CROSS JOIN &lt;/span&gt;t3 y &lt;span style="color:gray;"&gt;)
        &lt;/span&gt;&lt;span style="color:blue;"&gt;INSERT INTO &lt;/span&gt;DummyData &lt;span style="color:gray;"&gt;( &lt;/span&gt;Padding &lt;span style="color:gray;"&gt;)
        &lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;x&lt;span style="color:gray;"&gt;.&lt;/span&gt;Padding &lt;span style="color:blue;"&gt;from &lt;/span&gt;t4 x &lt;span style="color:gray;"&gt;CROSS JOIN &lt;/span&gt;t4 y &lt;span style="color:gray;"&gt;;
        
    &lt;/span&gt;&lt;span style="color:blue;"&gt;COMMIT &lt;/span&gt;&lt;span style="color:gray;"&gt;;
    
    &lt;/span&gt;&lt;span style="color:blue;"&gt;SET &lt;/span&gt;@i &lt;span style="color:gray;"&gt;= &lt;/span&gt;@i &lt;span style="color:gray;"&gt;+ &lt;/span&gt;1 &lt;span style="color:gray;"&gt;;
    
&lt;/span&gt;&lt;span style="color:blue;"&gt;END &lt;/span&gt;&lt;span style="color:gray;"&gt;;
        
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

CHECKPOINT &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:05' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;-- Here you can see the log usage for an index create:

&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE CLUSTERED INDEX &lt;/span&gt;clust &lt;span style="color:blue;"&gt;ON &lt;/span&gt;DummyData&lt;span style="color:gray;"&gt;( &lt;/span&gt;Padding &lt;span style="color:gray;"&gt;) ;

&lt;/span&gt;&lt;span style="color:blue;"&gt;CHECKPOINT &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:05' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;-- And this is where the &amp;quot;sawtooth&amp;quot; becomes visible:

&lt;/span&gt;&lt;span style="color:blue;"&gt;BEGIN TRANSACTION &lt;/span&gt;&lt;span style="color:gray;"&gt;;

    &lt;/span&gt;&lt;span style="color:blue;"&gt;UPDATE &lt;/span&gt;DummyData 
    &lt;span style="color:blue;"&gt;SET &lt;/span&gt;Padding &lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:magenta;"&gt;REPLICATE&lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:red;"&gt;'z'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;800 &lt;span style="color:gray;"&gt;) ;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:02' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;-- Log use drops here:

&lt;/span&gt;&lt;span style="color:blue;"&gt;COMMIT &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:02' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;BEGIN TRANSACTION &lt;/span&gt;&lt;span style="color:gray;"&gt;;

    &lt;/span&gt;&lt;span style="color:blue;"&gt;UPDATE &lt;/span&gt;DummyData 
    &lt;span style="color:blue;"&gt;SET &lt;/span&gt;Padding &lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:magenta;"&gt;REPLICATE&lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:red;"&gt;'z'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;800 &lt;span style="color:gray;"&gt;) ;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:02' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;-- Log use drops here:

&lt;/span&gt;&lt;span style="color:blue;"&gt;COMMIT &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:02' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;BEGIN TRANSACTION &lt;/span&gt;&lt;span style="color:gray;"&gt;;

    &lt;/span&gt;&lt;span style="color:blue;"&gt;UPDATE &lt;/span&gt;DummyData 
    &lt;span style="color:blue;"&gt;SET &lt;/span&gt;Padding &lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:magenta;"&gt;REPLICATE&lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:red;"&gt;'z'&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;800 &lt;span style="color:gray;"&gt;) ;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:02' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;-- Log use drops here:

&lt;/span&gt;&lt;span style="color:blue;"&gt;COMMIT &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;WAITFOR DELAY &lt;/span&gt;&lt;span style="color:red;"&gt;'00:00:02' &lt;/span&gt;&lt;span style="color:gray;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;USE master &lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO

DROP DATABASE &lt;/span&gt;LogDemo &lt;span style="color:gray;"&gt;;
&lt;/span&gt;&lt;span style="color:blue;"&gt;GO&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The best way to try this out is probably to highlight and execute a few lines at a time, and watch Performance Monitor to see if it does what you expect. Happy logging!&lt;/p&gt;</description></item></channel></rss>