![]() |
Minimizing data loss when accidents happens |
|
Home About me and Nucleus Partners Articles, tips etc. My blog Links Microsoft articles Forums Course demo files ![]() |
Overview "Help! I just deleted all rows in the invoice table! Can you undo the operation?" You might have been there? Chances are that the operation wasn't performed inside a transaction, which mean that you are probably in for a RESTORE operation. Say that the mistake was performed at 15:45. The user is well trained and came to you immediately after the mistake (we allow 5 minutes for some agony), which mean the user came to you at 15:50. A database backup is performed every night at 01:00 and the transaction log is backed up every hour. Versions This article applies to SQL Server 2000, 2005 and 2008. Options
1. Restore the most recent database backup. This one is obvious. You will lose all work performed that day. Not acceptable in most situations. 2. Restore the most recent database backup and all subsequent log backups. (Requires full or bulk_logged recovery model and proper handling of transaction log backups.) This is also rather obvious. You will lose all work performed since 15:00. Might be acceptable, but we can do better. 3. Perform a log backup, restore the most recent database backup and all subsequent log backups (including the very last one). (Requires full or bulk_logged recovery model and proper handling of transaction log backups.) First you perform a regular transaction log backup. You now want to restore the database backup and all subsequent log backups. But you also need to specify STOPAT for the last log backup, else you will bring the database to the state of 15:52, and the accident has already happened. If you know when the accident happened, you just use that time (a few moments before, of course) for the STOPAT parameter in the final RESTORE LOG command. But what if you don't know the time when the accident happened? 3a. Get the time to stop from the transaction log backup. Unfortunately, SQL Server doesn't come with any log reader tools usable for this purpose. Sure, you have DBCC LOG and fn_loginfo(), but these will not provide you with readable information. If you want to read the log backup when the accident happened, you need to use some 3:rd party tool. I have listed the ones I know of on my links page. 3b. Restore the same last log backup several times to find out when the mistake happened. Another approach is to restore the same last log backup several times, pushing forward the time for the STOPAT parameter a little each time. After each restore, you do a SELECT or similar to find out whether the accident has happened yet. You now know when the accident happened (15:45), so you restart the restore operations and specify this time for the final log restore. The ability to restore the same log backup several times, pushing forward the STOPAT parameter a little, is a well hidden feature in SQL Server. I have checked with MS and this is a supported restore method. At then end of this article, you'll find a script which displays this. 4. Restore into another database and copy the affected data into the production database. The advantage with this technique is that you will only lose data for the affected table(s). Use any of above options, but restore into a new database. Then use INSERT SELECT, SELECT INTO, DTS or some other techniques to copy the data to your production database. The downside with this technique is that the database now has data from two different time periods. I.e., the database is potentially out-of-sync if you have relations inside the database or other time related dependencies (this should have been allowed unless that happened first, so you can't just unto "that"). And most databases do indeed have such relationships and dependencies. Ether explicitly defined using FOREIGN KEY constraints, transactions etc. or implicitly and hopefully maintained by the applications. Needles to say, this is only for the more advanced DBA who understand how the data relate and the consequences of doing this. 5. Use some tool which can generate "undo" operations from the transaction log and apply that script to your production database. (Don't expect this to be an option if you are in simple recovery model since SQL Server will empty the log by itself - i.e., log records most probably no longer around.) This step doesn't involve any restore. You use a 3:rd party tool which read the transaction log and based on that generates operations that effectively undo the mistake. See my links page for such tools. As with above, the data is at risk as there could be operations performed after the mistake that was based on the mistake actually took place! How much data did we lose? Common to scenario 1 to 3 is that we lose at least 7 minutes of work, from 15:45 (the accident) to 15:52 (when you got to work).
The script below creates a database with a table in it, and then does a BACKUP DATABASE. It also creates a temp table to keep track on when each INSERT operation is performed, to be used for the RESTORE operations. Then a number of INSERT operations are performed, with a delay of 5 seconds. The initial stage finishes with a BACKUP LOG. Finally, the RESTORE operations. First RESTORE DATABASE. Then a cursor is used over the temp table so we can restore the same log backup, using STANDBY so we can do SELECT in between each RESTORE and , of course, using a different time for each RESTORE operation. Warning: Below will delete a database named 'test', if such exists! -- Initial stage: create the database, tables, BACKUP DATABASE,
|