1

I'm preparing to test an application in development. The application uses SQL Server 2019 for backend databases. It allows users to maintain multiple databases (for compliance and regulatory reasons).

QA testing scenarios require databases to be restored frequently to a known state before a staff member performs test cases in sequence. They then note the results of the test scenario.

There are approximately a dozen test scenarios to work on for this release, and an average of 6 databases to be used for most scenarios. For every scenario, this setup takes about 10 minutes and involves over 20 clicks.

Since scenarios will be tested before and after code changes, this means a time commitment of about 8 hours on setup alone. I suspect this can be reduced to about 1 minute since most of the time is spent navigating menus and the file system while restorations only take a few seconds each.


So I'd like to automate restorations. How can I automate the following sequence of operations inside of SSMS?

  1. Drop all user created databases on the test instance of SQL Server
  2. Create new or overwritten databases populated from ~6 .BAK files. I currently perform this one-by-one using "Restore Database", then adding a new file device, and finally launching the restorations.

EDIT: I usually work with SQL, C#, Batchfiles, or Python. But this task allows flexibility as long as it saves time and the restoration process is reliable. I would imagine either SSMS or a T-SQL query are the natural first places for me to begin.


We are currently using full backups and these seem to remain connected to their parent SQL Server instance and database. This caused me to encounter an SSMS bug when attempting to overwrite an existing database with a backup from another database on the same instance -- the restore fails to overwrite the target database, and the database that created the backup becomes stuck "restoring" until SSMS is closed or I manually restore it with the correct backup.

So as a minor addendum, what backup settings are appropriate for creating these independent copies of databases that have been backed up from other SQL Server instances?

Aaron
  • 13
  • 4
  • Automate it how? Do you have a favored programming language and could you deploy a app? Do you have some kind of pipeline that can run scripts, for example PowerShell? Do you require that it be done through a T-SQL script that's run in SSMS? If it were up to me I'd seek to eliminate all of those staff members that are performing tests as well, and (at most) have them curate an automated test runner instead (as in, ensuring no changes to it are made and what you see in the tests is what you get). Leave no room for fat fingers to fumble. – Jeroen Mostert Jul 28 '22 at 18:05
  • To a first approximation, automating your current restores is as simple as using that handy "Script" button that SSMS produces at the top of the window, when you're done configuring all the bells and whistles, right before you hit "OK", and keeping the location of your backups constant. Making this more fancy to account for variables would be step 2. This would also allow you to inspect and manually run the statements to see what errors occur - a DB getting stuck in the "restoring" state is normally not an SSMS bug but a user error of some sort. Backups are *not* associated with servers. – Jeroen Mostert Jul 28 '22 at 18:06
  • Ah I see. I'm most familiar with the SSMS user interface. But I'm more satisfied with any method of automation as long as I can dump the .BAKs in one directory and launch the restore with minimal clicks to overwrite/create any databases. So if it can be done using a SQL query (or PowerShell) and less than a few dozen lines of boilerplate, that's more than great! – Aaron Jul 28 '22 at 18:15

1 Answers1

0

I would suggest you utilize Database Snapshots instead. This allows you to take a snapshot of the database, and then revert back to it after changes are made. The disk space taken up by the snapshot is purely the difference in changes to pages, not the whole database.

Here is a script to create database snapshots for all user databases (you cannot do this for system DBs).

DECLARE @sql nvarchar(max);

SELECT @sql =
  STRING_AGG(CAST(CONCAT(

    'CREATE DATABASE ',
    QUOTENAME(d.name + '_snap'),
    ' ON ',
    f.files,
    ' AS SNAPSHOT OF ',
    QUOTENAME(d.name),
    ';'
   )
   AS nvarchar(max)), '
'  )
FROM sys.databases d
CROSS APPLY (
    SELECT
      files = STRING_AGG(CONCAT(

        '(NAME = ',
        QUOTENAME(f.name),
        ', FILENAME = ''',
        REPLACE(f.physical_name + 'snap', '''', ''''''),
        ''')'

       ), ',
'    )
    FROM sys.master_files f
    WHERE f.database_id = d.database_id
      AND f.type_desc = 'ROWS'
) f
WHERE d.database_id > 4;  -- not system DB

PRINT @sql;

EXEC sp_executesql @sql;

And here is a script to revert to the snapshots

DECLARE @sql nvarchar(max);

SELECT @sql =
  STRING_AGG(CAST(CONCAT(

    'RESTORE DATABASE ',
    QUOTENAME(dSource.name),
    ' FROM DATABASE_SNAPSHOT = ',
    QUOTENAME(dSnap.name),
    ';'
   )
   AS nvarchar(max)), '
'  )
FROM sys.databases dSnap
JOIN sys.databases dSource ON dSource.database_id = dSnap.source_database_id;

PRINT @sql;

EXEC sp_executesql @sql;

And to drop the snapshots:

DECLARE @sql nvarchar(max);

SELECT @sql =
  STRING_AGG(CAST(CONCAT(

    'DROP DATABASE ',
    QUOTENAME(d.name),
    ';'
   )
   AS nvarchar(max)), '
'  )
FROM sys.databases d
WHERE d.source_database_id > 0;

PRINT @sql;

EXEC sp_executesql @sql;
Charlieface
  • 52,284
  • 6
  • 19
  • 43
  • Thank you, this approach is very well suited to my current usecase. I'm a little bit surprised at how intricate the process of restoring is, but this is an excellent recommendation. – Aaron Jul 29 '22 at 22:39
  • Not sure what's intricate about it: it's just `RESTORE DATABASE SomeDB FROM DATABASE_SNAPSHOT = SomeSnapshot` the script is just to do it in bulk – Charlieface Jul 30 '22 at 22:11
  • Fair enough. More along the lines of how difficult it is to do in bulk from the SQL Server Management Studio. I had a similar script for running restores from full backups, but there were issues due to some of the logical files not being part of the DBs. Now there's been some time for other answerers. I'll happily mark yours as the solution, even though I can't upvote yet. Thanks again! – Aaron Aug 02 '22 at 16:22