Man!!!! Why is the code to create a database snapshot so ridiculously complicated? Actually, I guess I understand why but how about allowing it to be done through SSMS and then setting a bunch of the parameters as defaults for us? Come on Microsoft! Help a SQL brother out!
Well luckily, where Microsoft fails, I’m there for you. Here’s my brilliant proc which will automatically create a database snapshot for you. It places the snapshot in the same physical location as the physical file in the snapshot. I think this will be fine in most environments but if you’re running tight on disk space or expect your snapshots to get pretty big you’ve been warned!
I create the proc in a database to hold various utility scripts. I creatively called my database: DBA. Catchy right?
USE DBA
GO
CREATE PROCEDURE usp_CreateDBSnapshot @DBName sysname
AS
/******************************************************************
Sample exec:
exec usp_CreateDBSnapshot 'MyDatabaseName'
2016-07-29 Steffek Initial Version. sqldbpros.com
******************************************************************/
DECLARE
@Sql NVARCHAR(MAX)
, -- holds dynamic sql
@Params NVARCHAR(MAX)
, -- hold dynamic sql parameters
@SnapshotDate VARCHAR(8)
, -- current date
@DBFiles NVARCHAR(MAX)
, -- holds list of data files and paths to create
@DBSnapshotName NVARCHAR(MAX);
SET @SnapshotDate = CONVERT(VARCHAR(8), GETDATE(), 112)
SET @DBSnapshotName = @DBName + '_Snapshot_' + @SnapshotDate
-----------------------------
-- get snapshot files from database_files
-----------------------------
SELECT
@Sql = N'
SELECT @DBFiles =
(SELECT '','' + ''(Name = '' + NAME + '', FILENAME = '' + CHAR(39) +
REVERSE(SUBSTRING(REVERSE(physical_name)--Reverse the string since the data we want to remove is at the end.
, PATINDEX(''%.%'', REVERSE(physical_name)) + 1--parse off the file extension by looking for the period.
,
len (physical_name)
)) +''_'' + @SnapshotDate + ''.ss'' + CHAR(39) + '')''
FROM ' + @DBName + '.sys.database_files
WHERE TYPE = 0
FOR XML PATH('''') ) '
--PRINT @sql
SELECT
@Params = N'@DBFiles nvarchar(MAX) OUTPUT, @SnapshotDate varchar(8)'
EXEC sp_executesql
@Sql
,@Params
,@DBFiles = @DBFiles OUTPUT
,@SnapshotDate = @SnapshotDate;
SELECT
@Sql = N'
USE ' + @DBName + ';
CREATE DATABASE ' + @DBSnapshotName + '
ON ' + STUFF(@DBFiles, 1, 1, '') + '
AS SNAPSHOT OF ' + @DBName + ';'
-------------------
-- create snapshot
-------------------
--PRINT @Sql
EXEC sp_executesql
@Sql
PRINT 'created database snapshot: ' + @DBSnapshotName
What do you think? Handy? Suggested improvements? Bring it on!