Using T-SQL Snapshot Backup: Point-in-time Recovery

This article guides you through how to use the T-SQL snapshot backup feature in SQL Server 2022 for point-in-time recovery of a database.

Point-in-time Recovery

9 minutes

Summary

T-SQL snapshot backup is a new feature in SQL Server 2022 that enables you to perform point-in-time database restores using a snapshot backup as the base of the restore.

image_pdfimage_print

This blog on point-in-time recovery originally appeared on www.nocentino.com. It has been republished with permission from the author.

In this post, the second in our series, I will guide you through using the new T-SQL snapshot backup feature in SQL Server 2022 to take a snapshot backup and perform point-in-time database restores using a snapshot backup as the base of the restore. We will explore how to manage storage-level operations, such as cloning snapshots and executing an instantaneous point-in-time restore of a database from the snapshot with minimal impact on your infrastructure. Additionally, I will demonstrate a PowerShell script that utilizes dbatools and the PureStoragePowerShellSDK2 modules to automate the process.

You can grab the whole script for this blog post on GitHub.

Taking a T-SQL Snapshot Backup

In the previous post in this series, “Using T-SQL Snapshot Backup: Are Snapshots Backups?” we covered the theory of using T-SQL snapshot backup for backup and restore operations. Now let’s get down to business and walk through the process of taking a T-SQL snapshot backup.

Initialize the Script’s Variables and Connections

  • To begin, we’ll set up some PowerShell variables to establish a connection to our SQL Server. We’ll also set some variables describing where our primary storage is, a Pure Storage® FlashArray system, and which volumes contain our databases. I’m utilizing dbatools and the Pure Storage PowerShell SDK2 to manage this process.
  • I am using the dbatools module here because it allows me to create a persistent SMO connection to our SQL instance and use it across multiple cmdlet calls in my script. Unlike the Invoke-SqlCmd from the SqlServer module, which establishes a connection, executes the query, and then disconnects the session. If we use Invoke-SqlCmd to initiate the database freeze, the database will immediately thaw when the session disconnects. Since dbatools maintains the connection, the database will remain frozen even after executing the cmdlet. To do this, I establish the SMO connection using Connect-DbaInstance, store the connection in $SqlInstance, and then pass it across various cmdlet calls, ensuring that the same SPID/connection is reused within SQL Server.
  • Let’s get some information about our database; take note of the size (in MB). That’s a pretty big database, nearly 3.5TB on disk. We’re going to restore it nearly instantly later on in this script. Who’s excited?

Connect to Our Storage Environment

  • In order to connect to the FlashArray’s REST API, we will prompt for user credentials. These will be used to create a connection object stored in the $FlashArray variable for subsequent operations in the script, including taking a storage-based snapshot after freezing the database for write IO.

Taking a T-SQL-based Snapshot Backup

  • Next, we need to freeze the database for write operations. We will create a query string for the T-SQL we want to run and then pass that string as a parameter to Invoke-DbaQuery. This code reuses the $SqlInstance SMO connection that was established earlier, so when this code finishes running, the database will still be frozen for write IO. I added the -Verbose flag to expose some additional information. In the output, you can see the backup locks being acquired and the output confirming that the database is frozen for write IO.
  • Next, take a snapshot of the Protection Group while the database is frozen for write IO. This snapshot will contain an application-consistent set of data that can be used for restores, replicated to other arrays in the same site, or transferred between sites for disaster recovery. In the output below, you can see the information returned when taking a snapshot on a FlashArray. Let’s store this information in the variable $Snapshot so we can use it later to encode some of these details in the metadata-only backup file’s header.
  • Now, it’s time to take a metadata-only backup. The metadata-only backup file name is dynamically generated using the database name and the current date. The backup command contains the database name $DbName, the backup file location TO DISK=’$BackupFile’, and the WITH METADATA_ONLY option to specify that it’s a snapshot backup without copying the data. The MEDIADESCRIPTION part stores the snapshot and FlashArray names in the backup metadata as a pipe-delimited string. This information can help locate the snapshot associated with this metadata-only backup file. Finally, the T-SQL snapshot backup is executed using the cmdlet Invoke-DbaQuery, which writes the metadata-only backup file to the specified location after thawing the database if successful.
    I am using the verbose flag again. When the command is executed, the output will show that the database is thawed, write IO is resumed, and the backup locks are released. Additionally, it will produce output similar to that of a full backup, reporting the number of pages copied from the database files. However, in this case, it will show that 0 pages are copied because we are performing a METADATA_ONLY snapshot backup.
  • Now that we have a snapshot backup as a base for a full database restore, let’s take a log backup so that we can later showcase how to perform a point-in-time recovery.

What Does SQL Server Think Happened?

  • Let’s check the SQL Server error log to see what SQL Server thinks happened. Here you can see that the snapshot backup process begins for Database1. The database option suspend_for_snapshot_backup is set to ON, and the database acquires backup locks, and freezes I/O operations. Then, after we take our METADATA_ONLY snapshot backup, the I/O operations for Database1 are resumed, and the backup locks are released. The log reports that the backup operation completes successfully, and we see that again 0 pages are being copied.
  • The backup is recorded in MSDB as a full backup with a snapshot.
  • Let’s take a look at the information in the backup header. Here, I’ve summarized important details such as “BackupType,” “BackupPath,” and data size. This header format is consistent across all backup types in SQL Server. As you develop automation processes around this feature, it should be familiar territory for a DBA.
snapshots backups
Point-in-time Recovery
T-SQL Snapshot Backup

Performing a Point-in-time Restore from a T-SQL Snapshot Backup

Now that we have a T-SQL snapshot backup and a log backup, let’s perform a point-in-time restore using these two backups.

  • First, we need to take the database offline, which we’d have to do anyway if we were restoring a full backup.
  • Since this is a storage-level operation, the volume of the database files needs to be taken offline.
  • By using the following code, I can retrieve the MEDIADESCRIPTION from the metadata-only backup file, where we stored the pipe-delimited string containing the location of FlashArray where the snapshot is located and the snapshot name. I’m storing this information in the variables $ArrayName and $SnapshotName. This is a crucial part of any snapshot backup plan as it allows us to accurately identify the snapshot associated with the metadata-only file. In this case, the FlashArray is flasharray1.example.com and the snapshot name on that array is SqlServer1-pg.2121, which contains our backup.
  • In this example, we are performing an in-place database restore. This process involves overwriting the current volume with the contents of the snapshot and reverting the database to its previous state. On a Pure Storage FlashArray (or Pure Cloud Block Store™), the cmdlet “New-Pfa2Volume” is used to clone a snapshot. In this code, we are overwriting the volume’s contents with the snapshot’s contents to revert the database to its previous state.
  • In our previous post, we discussed additional restore scenarios. We could clone to a new set of volumes on the same instance, restoring the database with a new name. Alternatively, we could clone the volumes to another instance of SQL Server.
  • After restoring the data to its original state, let’s bring the disk back online.
  • With the database files physically in place and reverted back in time, we can use the following code to create the RESTORE command as a string: RESTORE DATABASE $DbName to initiate the restore process and specify the location of the metadata-only backup file using the FROM DISK = ‘$BackupFile’ option. Since this is a T-SQL snapshot backup-based restore, we need to include the METADATA_ONLY option, which informs the database engine not to copy the pages during the restore process. Additionally, we should incorporate the REPLACE option to overwrite the existing database and include the NORECOVERY option to keep the database in RESTORING mode after the command is executed. If you wish to bring the database online at this point, you can omit the NORECOVERY option. The Invoke-DbaQuery command is used to execute the query string and initiates the restore process.
  • The full restore duration includes the instant snapshot revert and about one second of database operations. That’s just wild!
  • With the full restore completed, let’s check the database’s current status. It’s in RESTORING mode.
  • Now, it’s time to perform the log restore. I am leaving the database in the RESTORING mode by adding the -NoRecovery parameter.
  • With the restore complete, let’s online the database.
  • Let’s again check the current state of the database…it’s ONLINE.

How Long Did the Backup Take?

Lastly, let’s look at how long this process takes, from freezing the database for a consistent snapshot to creating the snapshot on our FlashArray and performing a metadata-only backup. In my lab, this usually takes 400ms-800ms. But remember, the freeze is only for writes, so it is very fast and only impacts writes. When the database is frozen, you can measure it using the WRITELOG wait type. Most applications can tolerate a write IO freeze of a few hundred milliseconds. Also, it’s likely that you’ll perform this operation during a maintenance window.

Wrapping Things Up

In this post, which is the second in our series, we used the T-SQL snapshot backup feature for point-in-time recovery of a database. Consider the business impact of this capability. You can perform an instantaneous full database restore and control your precise recovery point with a point-in-time restore.You can grab the whole script for this blog post on GitHub.