Disaster recovery 101: backing up the tail of the log

(Check out my online training courses: SQL Server: Detecting and Correcting Database Corruption and SQL Server: Advanced Corruption Recovery Techniques. We can also help you with disaster recovery.)

One of the first things you should always check when a database has been damaged and you’re going to perform a restore operation is whether you need to back up the tail of the log.

The tail of the log contains the transaction log that’s been generated since the most recent log backup was taken. If you want to be able to recover right up to the point of the disaster, you need to be able to get those log records so they can be part of the restore sequence.

There are two cases to consider here 1) the server is still available 2) the server is not available. For case 1, you can just perform a regular tail-of-the-log backup. For case 2, you’ll need to hack-attach the log into another server to be able to back it up.

Case 1: tail-of-the-log backup when server is available

If the database is damaged but the server is still available, taking a tail-of-the-log backup is simple. The only exception is when there has been a minimally-logged operation performed in the BULK_LOGGED recovery model since the previous log backup – in that case a tail-of-the-log backup is not possible at all, and you’ll have lost all transaction log generated since the last log backup. See A SQL Server DBA myth a day: (28/30) BULK_LOGGED recovery model for more details.

When the data files are damaged and you want to take a log backup, you’ll get an error if you try to back up the log normally.

As an example, I’ll create a database and put some transactions in it:

CREATE DATABASE [DBMaint2008];
GO
USE [DBMaint2008];
GO

CREATE TABLE [TestTable] ([C1] INT IDENTITY, [C2] CHAR (100));
GO

-- Take a full backup
BACKUP DATABASE [DBMaint2008] TO DISK = N'D:\SQLskills\DemoBackups\DBMaint_Full.bck' WITH INIT;
GO

-- Insert some rows
INSERT INTO [TestTable] VALUES ('Transaction 1');
INSERT INTO [TestTable] VALUES ('Transaction 2');
GO

-- Take a log backup
BACKUP LOG [DBMaint2008] TO DISK = N'D:\SQLskills\DemoBackups\DBMaint_Log1.bck' WITH INIT;
GO

-- Insert some more rows
INSERT INTO [TestTable] VALUES ('Transaction 3');
INSERT INTO [TestTable] VALUES ('Transaction 4');
GO

Now disaster will strike – I’ll do the following to simulate a disaster:

  1. ALTER DATABASE [DBMaint2008] SET OFFLINE;
  2. Delete the data file

If I try to then access the database, I’ll get:

ALTER DATABASE DBMaint2008 SET ONLINE;
GO
Msg 5120, Level 16, State 101, Line 1
Unable to open the physical file "C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\DBMaint2008.mdf". Operating system error 2: "2(The system cannot find the file specified.)".
Msg 945, Level 14, State 2, Line 1
Database 'DBMaint2008' cannot be opened due to inaccessible files or insufficient memory or disk space.  See the SQL Server errorlog for details.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.

So I’ll try a normal log backup:

BACKUP LOG [DBMaint2008] TO DISK = N'D:\SQLskills\DemoBackups\DBMaint_Log_Tail.bck' WITH INIT;
GO
Msg 945, Level 14, State 2, Line 1
Database 'DBMaint2008' cannot be opened due to inaccessible files or insufficient memory or disk space.  See the SQL Server errorlog for details.
Msg 3013, Level 16, State 1, Line 1
BACKUP LOG is terminating abnormally.

It doesn’t work – as the data files aren’t all accessible.

The trick is to use the NO_TRUNCATE option, which allows the log backup even if the database files aren’t there:

BACKUP LOG [DBMaint2008] TO DISK = N'D:\SQLskills\DemoBackups\DBMaint_Log_Tail.bck' WITH INIT, NO_TRUNCATE;
GO
Processed 2 pages for database 'DBMaint2008', file 'DBMaint2008_log' on file 1.
BACKUP LOG successfully processed 2 pages in 0.010 seconds (0.972 MB/sec).

I can then use the tail-of-the-log backup as the final backup in the restore sequence, saving transactions 3 and 4 from above. Try it for yourself.

Case 2: tail-of-the-log backup when server is no longer available

This is the case where the server crashed and cannot be brought online. If you have access to all the data and log files for the database, you can attach it to another server and crash recovery will run automatically. If you only have access to the log file, you’ll need to perform some extra steps to allow a tail-of-the-log backup to be performed – basically performing what I call a hack-attach.

Assuming I’ve run the script above to setup the database, this time I’ll do the following to simulate a server-crash disaster:

  1. ALTER DATABASE [DBMaint2008] SET OFFLINE;
  2. Delete the data file
  3. Copy the log file somewhere else
  4. DROP DATABASE [DBMaint2008];

Now all I have is some backups and a log file. I’ll need to attach the log file to SQL Server somehow so that I can perform the vital tail-of-the-log backup. The way to do it is:

  1. Create a dummy database with the same name as the one that we’re interested in (make sure you have instant file initialization enabled so the file creations don’t take ages – see this blog post)
  2. Set the database offline (or shutdown the server)
  3. Delete all the files from the dummy database
  4. Drop in the log file from our real database

Like so for steps 1 and 2:

CREATE DATABASE [DBMaint2008];
GO
ALTER DATABASE [DBMaint2008] SET OFFLINE;
GO

Now I’ll perform steps 3 and 4.

I need to attempt to bring the database online again:

ALTER DATABASE [DBMaint2008] SET ONLINE;
GO
Msg 5120, Level 16, State 101, Line 1
Unable to open the physical file "C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\DBMaint2008.mdf". Operating system error 2: "2(The system cannot find the file specified.)".
Msg 945, Level 14, State 2, Line 1
Database 'DBMaint2008' cannot be opened due to inaccessible files or insufficient memory or disk space.  See the SQL Server errorlog for details.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.

And then I can perform the tail-of-the-log backup as before, and use it to recover everything up to the point of the disaster.

Note: This procedure does not work if I try to perform the hack-attach to a more recent version of SQL Server. I tried hacking a 2005 log into a 2008 server and taking the tail-of-the-log backup – which worked fine, but the tail-of-the-log backup could not be used in conjunction with the first set of backups from the 2005 server. The reason for this is that the database version number in the tail-of-the-log backup is 655 (SQL Server 2008) and those for the 2005 backups are 611 (SQL Server 2005). The database doesn’t get upgraded when restoring on the 2008 server until the end of the restore sequence – so as far as the 2008 server is concerned, my 2008 tail-of-the-log backup can’t be used in the restore sequence of a still-2005-really database. Hope that makes sense!

Summary

Checking whether a tail-of-the-log backup is required is essential during a disaster recovery, and it’s not hard to do. As with any disaster recovery procedures, make sure you’ve practiced doing it in advance!

21 thoughts on “Disaster recovery 101: backing up the tail of the log

  1. Paul,

    Just want to say thanks for posting this. I’ve never been in a scenario where I’ve had something like this happen. But it’s always nice to be able to ‘rehearse’ the situation so that when it does happen (and it will happen) I can be prepared.

  2. I like to read your posts with great interest.
    I run your scenario on a SQL Server 2008 SP1 instance and when I reached the part of:
    "The trick is to use the NO_TRUNCATE option, which allows the log backup even if the database files aren’t there:

    BACKUP LOG DBMaint2008 TO DISK = ‘D:\DBMaint_Log_Tail.bck’ WITH INIT, NO_TRUNCATE;
    GO "
    It failed with the following error:
    File activation failure. The physical file name "C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\DBMaint2008_log.LDF" may be incorrect.
    Msg 3447, Level 16, State 1, Line 1
    Could not activate or scan all of the log files for database ‘DBMaint2008’.
    Msg 3013, Level 16, State 1, Line 1
    BACKUP LOG is terminating abnormally.

    With which version did you work?
    What is the meaning of the error

  3. Great Post Paul! Will keep this in my list. hope I never have to use it. But will come handy in case of a need. Will have to practise the steps atleast once to make sure I understand it right!..:)

    Thanks,
    Suresh.

  4. thinking back on the steps to recover, I almost forgot about ‘NO_TRUNCATE’ option..:) while recovering logs.. This is such an important option..

  5. Hi,

    After setting the database to offline mode, I deleted the data file only. Then I tried to take the tail log backup but it wont allow me. It gives me the same following error :

    Msg 946, Level 14, State 2, Line 1
    Cannot open database ‘Sample’ version 0. Upgrade the database to the elp latest version.
    Msg 3013, Level 16, State 1, Line 1
    BACKUP LOG is terminating abnormally.

    Please Help !
    Thanks,
    Santosh

  6. Great article, I need to know this if & when.
    In testing this, I caught a syntax error on line 6, the first Create Table. The semi-colon seemed to be the hangup, removed it and it completed successfully. Is it a typo or version-dependent syntax, please explain. Cheers

  7. Thank you Paul. This post is invaluable. It’s a great reminder for me to practice it periodically since you never know when you’ll need it.

  8. One thing I noticed about SSMS is that when doing a Restore, it creates the Tail-Log BACKUP with NORECOVERY Command as Step 1,
    then the full/diff/tranlog series of RESTORE commands, then….it forgets to re-apply the Tailog backup!
    The Tail log file created is NOT REFERENCED AT ALL
    The Tail of the Log is backed up, but not restored
    AKA the Data in the log which the TLog backup “preserved” is not re-applied back to the Database
    Its effectively lost, although in the BAK file it created as Step 1

    I ALWAYS have to modify the Backup Script SSMS creates to apply the Taillog if I want it
    The other reason I usually dont EVER do a tail log is that it usually includes garbage,
    AKA an UPDATE statement with no WHERE clause
    Re-Applying the tail log of that backup re-inserts that data and Im back to square one

    unless im missing something

      1. Thanks for confirming!
        Colleague of mine says ALWAYS Create and ALWAYS Restore a TailLog
        Well, not if you want to go back to the Last Tran

Leave a Reply

Your email address will not be published. Required fields are marked *

Other articles

Imagine feeling confident enough to handle whatever your database throws at you.

With training and consulting from SQLskills, you’ll be able to solve big problems, elevate your team’s capacity, and take control of your data career.