THE SQL Server Blog Spot on the Web

Welcome to SQLblog.com - The SQL Server blog spot on the web Sign in | Join | Help
in Search

Tibor Karaszi

Table restore and filegroups

The story usually goes something like:

Q - How can I restore only this table?
A - Put it on its own filegroup and you can do filegroup level backup and restore.

The problem with above answer is that it most likely misses the point. We need to ask ourselves:
Why do you want to do a table level restore?

The answer to the question is very often that the table need to be reverted to an earlier point in time, possibly because some accident happened; like deleting all rows in the table by mistake. (See my minimizing data loss when accidents happens article for a more general discussion.) So, why is not filegroup backup that usable for this scenario?

SQL Server will not let you into a database where different data is from different points in time!
(2005+, Enterprise Edition and Developer Edition, has online restore which allow you into the database but you wont be able to access the restored data until you make it current - so it doesn't really changes the basic issue here.)

Now, think about above. If we restore the filegroup backup containing the emptied table, but then need to restore all subsequent log backups up to "now", what good did this song-and-dance-act do us? No good at all (except for a learning experience, of course).
We can of course restore the primary filegroup and the one with the damaged data into a new temp database - to the desired earlier point in time, and then copy the relevant data from this temp database into the production database. But this operation is certainly not as straight forward as just restoring the filegroup backup into the production/source database.

Now, about having data from different point in time (regardless of how you achieve it): Handle with care. Just think about relationship and dependencies you have inside a database. Reverting some table to an earlier point in time can cause havoc for those dependencies.

I won't get into details about how filegroup backups work, online restore, the PARTIAL option of the restore command etc. - you can read about all that in Books Online. The point about this blog is to have somewhere I can point to when I see the "put-the-table-on-its-own-filegroup-and-backup-that-filegroup" recommendation.

As usual, I have a TSQL script to display my points. If you happen to think that it *is* possible to restore part of the database to an earlier point in time into the production/source database - I'm all ears. You can post a comment here, I will be notified. Please use below script as a template, and modify so that we can execute it and re-execute it.
The usual disclaimer is to not execute below if you don't understand what it is doing, etc.

 

--Drop and create the database
USE master
IF DB_ID('fgr'IS NOT NULL DROP DATABASE fgr
GO
--Three filegroups
CREATE DATABASE fgr ON  PRIMARY 
NAME N'fgr'FILENAME 'C:\fgr.mdf'), 
 
FILEGROUP fg1 
NAME N'fg1'FILENAME 'C:\fg1.ndf'), 
 
FILEGROUP fg2 
NAME N'fg2'FILENAME 'C:\fg2.ndf')
 
LOG ON 
NAME N'fgr_log'FILENAME 'C:\fgr_log.ldf')
GO
ALTER DATABASE fgr SET RECOVERY FULL

--Base backup
BACKUP DATABASE fgr TO DISK = 'C:\fgr.bak' WITH INIT
GO

--One table on each filegroup
CREATE TABLE fgr..t_primary(c1 INTON "PRIMARY"
CREATE TABLE fgr..t_fg1(c1 INTON fg1
CREATE TABLE fgr..t_fg2(c1 INTON fg2

--Insert data into each table
INSERT INTO fgr..t_primary(c1VALUES(1)
INSERT INTO fgr..t_fg1(c1VALUES(1)
INSERT INTO fgr..t_fg2(c1VALUES(1)

BACKUP LOG fgr TO DISK = 'c:\fgr.trn' WITH INIT --1

--Filegroup backup of fg2
BACKUP DATABASE fgr FILEGROUP 'fg2' TO DISK = 'C:\fgr_fg2.bak' WITH INIT

BACKUP LOG fgr TO DISK = 'c:\fgr.trn' WITH NOINIT --2

--Delete from t_fg2
--Ths is our accident which we want to rollback!!!
DELETE FROM fgr..t_fg2

BACKUP LOG fgr TO DISK = 'c:\fgr.trn' WITH NOINIT --3

--Now, try to restore that filegroup to previos point in time
RESTORE DATABASE fgr FILEGROUP 'fg2' FROM DISK = 'C:\fgr_fg2.bak'
GO

SELECT FROM fgr..t_fg2 --error 8653
GO

--If we are on 2005+ and EE or Dev Ed, the restore can be online
--This means that rest of the database is accessible during the restore
INSERT INTO fgr..t_fg1(c1VALUES(2)
SELECT FROM fgr..t_fg1

--We must restore *all* log backups since that db backup
RESTORE LOG fgr FROM DISK = 'c:\fgr.trn' WITH FILE = --out of 3
RESTORE LOG fgr FROM DISK = 'c:\fgr.trn' WITH FILE = --out of 3
GO

SELECT FROM fgr..t_fg2 --Success
--We didn't get to the data before the accidental DELETE!
GO


----------------------------------------------------------------------------
--What we can do is restore into a new database instead,
--to an earlier point in time.
--We need the PRIMARY filegroup and whatever more we want to access
----------------------------------------------------------------------------
IF DB_ID('fgr_tmp'IS NOT NULL DROP DATABASE fgr_tmp
GO
RESTORE DATABASE fgr_tmp FILEGROUP 'PRIMARY' FROM DISK = 'C:\fgr.bak'
WITH
 
MOVE 'fgr' TO 'C:\fgr_tmp.mdf'
,MOVE 'fg2' TO 'C:\fg2_tmp.ndf'
,MOVE 'fgr_log' TO 'C:\fgr_tmp_log.ldf'
,PARTIALNORECOVERY

RESTORE DATABASE fgr_tmp FILEGROUP 'fg2' FROM DISK = 'C:\fgr_fg2.bak'

RESTORE LOG fgr_tmp FROM DISK = 'c:\fgr.trn' WITH FILE = 1NORECOVERY
RESTORE LOG fgr_tmp FROM DISK = 'c:\fgr.trn' WITH FILE = 2RECOVERY

--Now the data in PRIMARY and fg2 is accessible
SELECT FROM fgr_tmp..t_fg2

--We can use above to import to our production db:
INSERT INTO fgr..t_fg2(c1)
SELECT c1 FROM fgr_tmp..t_fg2

--And now the data is there again :-)
SELECT FROM fgr..t_fg2

Published Thursday, June 25, 2009 1:49 PM by TiborKaraszi
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

SQL Server said:

The story usually goes something like: Q - How can I restore only this table? A - Put it on its own filegroup

June 25, 2009 7:42 AM
 

DotNetShoutout said:

Thank you for submitting this cool story - Trackback from DotNetShoutout

June 25, 2009 8:02 AM
 

AllenMWhite said:

Tibor, in my last job as a DBA I had a set of databases controlling the graphical presentation of websites.  The web designers too frequently deleted objects in a website (deleting the table data supporting those objects), realizing later they were in the wrong website, and asked me to restore the table data.

The way I ended up resolving this was by creating a snapshot database for each one of these databases, one per day using the day of the week as the snapshot database name suffix.  Then the next week I'd delete the previous week's snapshot and create the new one.

This way, if on Tuesday the designer deleted data incorrectly and then told me about it on Thursday, I could select the deleted rows from Tuesday morning's snapshot and insert it into the current table.

Yes, I built scripts to automate the daily creation of the databases, and it is still working well in that environment.

Allen

June 25, 2009 12:42 PM
 

TiborKaraszi said:

Allen,

Did you use powershell? Sorry, I couldn't help myself. I *just* finished reading your WP on PS  - Good Stuff, some 2 minutes before I got email on your comment here... :-)

Interesting usage of Db Snapshot. I think we often overlook these simple-but-perhaps-not-obvious way of acheieving something. Sometimes I think that SQL Server is so stuffed with functionality and features so it is easy see only trees...

June 25, 2009 12:53 PM
 

Sankar Reddy said:

Allen,

Interesting approach but the only complaint I have is, SQL Server flushes the entire procedure when you drop a snapshot in 2005, corrected in 2008. It may NOT be a big problem in all environments but yes its a problem for some.

June 25, 2009 3:47 PM
 

AllenMWhite said:

Tibor, I created that solution before Microsoft introduced PowerShell, so it was done with VB/SMO and TSQL.  I'm glad you liked the WP. Thanks.

Sankar, in the environment for that application clearing the proc cache at 5am doesn't cause a problem, but that is an important consideration.

Allen

June 26, 2009 7:42 AM
 

Anwar said:

Allen, what if you couldn't make a snapshot because the size of a VLDB. Is the trigger or replication the best way to maintain a backup of small group of tables? I don't like very much the filegroups way :-(

July 6, 2009 3:36 PM
 

Weam Muhsen said:

Dear Sir,

Can I restore just one table from database backup

July 22, 2009 3:46 AM
 

TiborKaraszi said:

The most granular level of restore is the filegroup level. So, yes, you can restore a single table assumiung that is is alone on a separate filegroup. This should not be done into an existing database, unless you want to forward this table restore into current point in time.

July 22, 2009 4:18 AM
 

My Weekly Bookmarks for October 9th | Brent Ozar - SQL Server DBA said:

October 9, 2009 11:33 PM
 

Rajnish said:

Very nice article to understand filegroup backup/restore

November 3, 2009 5:48 AM

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server (Commercial Edition), by Telligent Systems
  Privacy Statement