Can individual filegroups be restored separately?

In this recent answer to a question on regarding the benefits of read-only filegroups, I posited that one might want to restore individual filegroups to enable a piece-meal approach to disaster recovery that allows the critical business data stored in one filegroup to be brought online very quickly, while still allowing other non-critical filegroups to be restored while the database is servicing business users.

In order to show how this works, I’ve created some test-bed code describing the steps necessary to complete this type of restore process.

First, we create a dummy database, named “fgRestoreTest”. The database will contain two filegroups, fg1 and fg2.:

Note the recovery model in the database is set to “FULL”, and we’ve completed a dummy “BACKUP DATABASE” command to ensure we are actually running the database in full recovery.

Now, let’s add some data into each filegroup. For purposes of this demo, we’ll consider fg1 to contain business-critical data, and fg2 to contain data that is only for reporting purposes, and therefore is not as critical. The typical scenario here would be the data on fg2 would be considerably larger than the data on fg1, even though each of our dummy tables only contains a single row.

Let’s take a backup of the database, then drop that sucker!

Here’s the juicy bit. We’ll restore the “primary” filegroup, along with the “fg1” filegroup, bringing the database online using the “RECOVERY” option.

Notice we’re using the FILEGROUP = 'x' syntax – this is the important part, since it tells SQL Server to only restore those particular filegroups. Note in our case the single backup we took contains all filegroups. Importantly, rollback of transactions that involve fg2 are deferred, since this filegroup is not available. Regular operations can continue, but locks are held by these transactions and log truncation will not occur until the rollback can complete.

Let’s see if we can query the tables in the database:

The above query returns rows:

| (No Column Name) | RestoreTestTable_ID |
| select #1        | 1                   |

However, querying dbo.RestoreTestTable_fg2 returns an error:

Since the filegroup containing dbo.RestoreTestTable_fg2 is not online, the query processor cannot even start generating a plan for the query, resulting in the error.

Msg 8653, Level 16, State 1, Line 1
The query processor is unable to produce a plan for the table or view 'RestoreTestTable_fg2' because the table resides in a filegroup which is not online.

In order to start restoring the fg2 filegroup, we must first take a “tail-of-the-log” backup, by specifying the “NORECOVERY” option as part of the “BACKUP LOG” command. Then we need to immediately start restoring the fg2 filegroup, using the “NORECOVERY” option, so we can then restore the tail-of-the-log backup. The restore of the log backup uses the “RECOVERY” option to allow SQL Server to run the recovery process on any outstanding transactions that might affect objects stored in all filegroups on the database:

Any ongoing transactions at the time of the initial backup (prior to the disaster) that spanned both the fg1 and fg2 database will be rolled-back or rolled-forward, as appropriate.

Once the above restores complete, we’re able to successfully query tables in both fg1 and fg2:

The results:

| (No column name) | RestoreTestTable_ID |
| select #3        | 1                   |

| (No column name) | RestoreTestTable_ID |
| select #4        | 1                   |


See the following MSDN resources for further details about this process:

Piecemeal Restores (SQL Server)
Example: Piecemeal Restore of Database (Full Recovery Model)