12
votes

I use sql server and have a huge database that partitioned by date in multiple file groups. the database filegroups is PRIMARY, FG2010, FG2011, FG2012, FG2013, and FG2014, that FG2010, FG2011, FG2012 and FG2013 is readonly.

Now, the backup scenario is:

each Friday get a full backup at 2:00 AM

each day on week except Friday get a differential backup at 2:00 AM

I want to change this scenario to:

get a full backup of database(One Time)

get a full backup of PRIMARY and FG2014 each Friday at 2:00 AM

get a differential backup of PRIMARY and FG2014 each day except Friday at 2:00 AM

Questions 1: Can I have this scenario?

I have a recovery plan too. each day I copy backup file to another server automatically by job and then restore it, in order to have recovery test plan and also use restored database to developer and tester users.

I want to have following scenario for recovery plan:

restore full backup of database.

restore last full backup of PRIMARY and FG2014.

restore last differential backup of PRIMARY and FG2014.

Question 2: can I have this scenario to recovery plan?

Question 3: can I have better scenario to backup and restore?

Please answer my question with TSQL query.

2
I think you could avoid to backup and restore every time the readonly filesgiammin
What is the recovery model for the database? I see no mention of transaction log backups and so assume SIMPLE is being used but would be grateful for confirmation, given the recovery model determines the Restore methods available for use.John Sansom

2 Answers

15
votes

Q1. Yes, you can. You would also need to be taking regular transaction log backups.

Q2. Yes, this would also work for a recovery strategy, again you need to be taking transaction log backups.

Q3. As you are using the backups to create a development database, I would stick with this. There are options such as log shipping but I would not implement them to keep a development database updated from production.

I have written some demo scripts which you can use to run through the scenario you suggested on your local instance.

The scripts will:-

  1. Create a test database, with multiple filegroups which some are read only.
  2. Create a development database from a backup of the test database.
  3. Take filegroup backups of the test database and restore over the development database

Please have a look and run through the scripts. Let me know if you have any questions.

Before you use the scripts, just make sure that you have the following filepaths on your computer:-

C:\SQLServer\Data
C:\SQLServer\Logs
C:\SQLServer\Backups

The version of SQL Server I use is 2012 SP2 CU2 Developer Edition.

First create the test database:-

CREATE DATABASE [FGRestoreTEST]
 ON  PRIMARY 
( NAME = N'FGRestoreTEST', FILENAME = N'C:\SQLServer\Data\FGRestoreTEST.mdf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 
 FILEGROUP [FG2010] 
( NAME = N'FG2010', FILENAME = N'C:\SQLServer\Data\FG2010.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 
 FILEGROUP [FG2011] 
( NAME = N'FG2011', FILENAME = N'C:\SQLServer\Data\FG2011.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 
 FILEGROUP [FG2012] 
( NAME = N'FG2012', FILENAME = N'C:\SQLServer\Data\FG2012.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 
 FILEGROUP [FG2013] 
( NAME = N'FG2013', FILENAME = N'C:\SQLServer\Data\FG2013.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 
 FILEGROUP [FG2014] 
( NAME = N'FG2014', FILENAME = N'C:\SQLServer\Data\FG2014.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
 LOG ON 
( NAME = N'FGRestoreTEST_log', FILENAME = N'C:\SQLServer\Logs\FGRestoreTEST_log.ldf' , SIZE = 2048KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO

Then create tables in each of the filegroups:-

USE [FGRestoreTEST];
GO

CREATE TABLE [PRIMARY_TABLE]
(ID INT,
 NAME CHAR(4)) ON [PRIMARY];

CREATE TABLE [FG2010_TABLE]
(ID INT,
 NAME CHAR(4)) ON [FG2010];

 CREATE TABLE [FG2011_TABLE]
(ID INT,
 NAME CHAR(4)) ON [FG2011];

CREATE TABLE [FG2012_TABLE]
(ID INT,
 NAME CHAR(4)) ON [FG2012];

CREATE TABLE [FG2013_TABLE]
(ID INT,
 NAME CHAR(4)) ON [FG2013];

CREATE TABLE [FG2014_TABLE]
(ID INT,
 NAME CHAR(4)) ON [FG2014];
 GO

Insert data (100 rows) into each of the tables:-

INSERT INTO [PRIMARY_TABLE]
SELECT 1, 'TEST'
GO 100

INSERT INTO [FG2010_TABLE]
SELECT 1, 'TEST'
GO 100

INSERT INTO [FG2011_TABLE]
SELECT 1, 'TEST'
GO 100

INSERT INTO [FG2012_TABLE]
SELECT 1, 'TEST'
GO 100

INSERT INTO [FG2013_TABLE]
SELECT 1, 'TEST'
GO 100

INSERT INTO [FG2014_TABLE]
SELECT 1, 'TEST'
GO 100

Then set certain filegroups to read only:-

ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2010] READ_ONLY;

ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2011] READ_ONLY;

ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2012] READ_ONLY;

ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2013] READ_ONLY;
GO

Take a full backup:-

USE [master];
GO

BACKUP DATABASE [FGRestoreTEST]
TO DISK = N'C:\SQLServer\Backups\FGRestoreTEST.BAK';
GO

Then create a development database from the full backup (this will be used to restore the filegroup backups that will be taken further next):-

RESTORE DATABASE [FGRestoreTEST_Dev]
FROM DISK = N'C:\SQLServer\Backups\FGRestoreTEST.BAK' WITH
MOVE 'FGRestoreTEST' TO 'C:\SQLServer\Data\FGRestoreTEST_Dev.mdf',
MOVE 'FG2010' TO 'C:\SQLServer\Data\FG2010_Dev.ndf',
MOVE 'FG2011' TO 'C:\SQLServer\Data\FG2011_Dev.ndf',
MOVE 'FG2012' TO 'C:\SQLServer\Data\FG2012_Dev.ndf',
MOVE 'FG2013' TO 'C:\SQLServer\Data\FG2013_Dev.ndf',
MOVE 'FG2014' TO 'C:\SQLServer\Data\FG2014_Dev.ndf',
MOVE 'FGRestoreTEST_log' TO 'C:\SQLServer\Logs\FGRestoreTEST_Dev_log.ldf',
RECOVERY,STATS=5;
GO

Take backups of each of the filegroups:-

--http://msdn.microsoft.com/en-us/library/ms189906.aspx
BACKUP DATABASE [FGRestoreTEST]
   FILEGROUP = 'PRIMARY'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_PRIMARY.bak';

BACKUP DATABASE [FGRestoreTEST]
   FILEGROUP = 'FG2010'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2010.bak';

BACKUP DATABASE [FGRestoreTEST]
   FILEGROUP = 'FG2011'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2011.bak';

BACKUP DATABASE [FGRestoreTEST]
   FILEGROUP = 'FG2012'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2012.bak';

BACKUP DATABASE [FGRestoreTEST]
   FILEGROUP = 'FG2013'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_G2013.bak';

BACKUP DATABASE [FGRestoreTEST]
   FILEGROUP = 'FG2014'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2014.bak';
GO

Now we will modify data in the Primary & FG2014 filegroups:-

USE [FGRestoreTEST];
GO

INSERT INTO [PRIMARY_TABLE]
SELECT 1, 'TEST'
GO 100

TRUNCATE TABLE [FG2014_TABLE];
GO

Take differential backups of the filegroups:-

BACKUP DATABASE [FGRestoreTest]
   FILEGROUP = 'PRIMARY'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_PRIMARYDIFF.bak'
   WITH DIFFERENTIAL;

BACKUP DATABASE [FGRestoreTest]
   FILEGROUP = 'FG2014'
   TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_FG2014DIFF.bak'
   WITH DIFFERENTIAL;
GO

Again, modify the data:-

USE [FGRestoreTEST];
GO

INSERT INTO [PRIMARY_TABLE]
SELECT 1, 'TEST'
GO 100

INSERT INTO [FG2014_TABLE]
SELECT 1, 'NEW'
GO 300

Backup the transaction log (you will probably have more than one of these in a real life environment, but for demo purposes I'm just taking one):-

USE [master];
GO

BACKUP LOG [FGRestoreTEST]
TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_LogBackup.trn';
GO

OK, now we can restore the development database. First we take a Tail Log backup, putting the database into recovery. Note:- we will not use this backup!

BACKUP LOG [FGRestoreTEST_Dev]
TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_TailLogBackup.trn'
WITH NORECOVERY;
GO

Now we can restore the full backups of the read-write filegroups:-

--http://msdn.microsoft.com/en-us/library/aa337540.aspx
--Restore primary filegroup
RESTORE DATABASE [FGRestoreTEST_Dev]
   FILEGROUP = 'PRIMARY'
   FROM DISK = 'C:\SQLServer\Backups\FGRestoreTEST_PRIMARY.bak'
   WITH NORECOVERY;
GO

--Restore FG2014 filegroup 
RESTORE DATABASE [FGRestoreTEST_Dev]
   FILEGROUP = 'FG2014'
   FROM DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2014.bak'
   WITH NORECOVERY;
GO

Then the differential backups:-

--Restore PRIMARY differential backup
RESTORE DATABASE [FGRestoreTEST_Dev]
   FILEGROUP = 'PRIMARY'
   FROM DISK = 'C:\SQLServer\Backups\FGRestoreTest_PRIMARYDIFF.bak'
   WITH NORECOVERY;
GO

--Restore FG2014 differential backup
RESTORE DATABASE [FGRestoreTEST_Dev]
   FILEGROUP = 'FG2014'
   FROM DISK = 'C:\SQLServer\Backups\FGRestoreTest_FG2014DIFF.bak'
   WITH NORECOVERY;
GO

Then the transaction log backup:-

RESTORE LOG [FGRestoreTEST_Dev]
FROM DISK = 'C:\SQLServer\Backups\FGRestoreTest_LogBackup.trn'
WITH NORECOVERY;
GO

Finally, the database can be recovered:-

RESTORE DATABASE [FGRestoreTest_DEV] WITH RECOVERY;
GO

And as a final test, check the data:-

USE [FGRestoreTEST_Dev];
GO

SELECT COUNT(*) AS [PRIMARY_TABLE]
FROM [PRIMARY_TABLE];

SELECT COUNT(*) AS [FG2010_TABLE]
FROM [FG2010_TABLE];

SELECT COUNT(*) AS [FG2011_TABLE]
FROM [FG2011_TABLE];

SELECT COUNT(*) AS [FG2012_TABLE]
FROM [FG2012_TABLE];

SELECT COUNT(*) AS [FG2013_TABLE]
FROM [FG2013_TABLE];

SELECT COUNT(*) AS [FG2014_TABLE]
FROM [FG2014_TABLE];

SELECT TOP (1) *
FROM [FG2014_TABLE];
GO

So, from the data changes made, we would expect to see 300 records in the PRIMARY & FG2014 filegroups, 100 in the rest and the all the values in the name column in the FG2014 set as 'NEW'.

2
votes

A1: Yes you can have this scenario however, the backup strategy does not provide an ongoing way to recover FG2010 through 2013 should there be a need to, as only a one time FULL database backup exists.

A2: Yes, with some tweaking. What you are wishing to implement is called a Piecemeal Restore and the bulk of the required instruction for the method required can be found in the Books Online Example: Piecemeal Restore of Only Some Filegroups.

The key difference is you will be restoring over a previously restored full database backup, rather than a live database that has experienced an issue with specific filegroups.

You should be easily able to create a test case/proof of concept for your needs swiftly by using the above reference. If you get stuck, add your attempt/code to question and the good community chaps here will provide guidance. With a little effort from you and some direction from the community, I'm sure you can answer your own question. Teach a man to fish and all that........