The most satisfying meal is the one you make yourself, and database backup jobs are no different.
Many DBAs use maintenance plans as a “one-stop-shop” for maintaining their SQL Server databases. After all, they do backups, integrity checks, index maintenance… What more could you possibly want?
But the truth of the matter is that maintenance plans are a lot like fast food: Yeah, you get the basics, but what if you have more specific needs in your environment that the “basics” can’t cover? You receive the SQL Server equivalent of a greasy, overworked sixteen-year-old giving you the stink-eye as they throw the “basics” in your bag anyway.
You’re left with two options: You either back up your databases with a third-party tool, or you set up your own backup job with SQL Server Agent. Today, we’ll be discussing the latter.
“But SQL Server Agent requires these things called ‘SCRIPTS’! Where am I going to get these?”
There are plenty of premade maintenance scripts out there (Ola Hallengren’s being one of the most famous and highly recommended), but we’re not here to talk about those. We’re here to make our own home-cooked backup solution.
Great. Now I’m craving Cracker Barrel.
The scripts I’m about to provide are a jumping-off point. They are by no means fully optimized for maximum performance (or any other DBA buzzwords); these are just examples of how even a junior or accidental DBA could throw together an automated backup script using basic T-SQL and programming logic (I use a WHILE loop instead of a cursor, for Pete’s sake!). Your mileage may vary, of course, given that different databases may have different backup needs—these are just scripts for full and log backups, the bare minimum in the backup world. There is plenty of room for customization and especially improvement, but these should help you get started in most cases.
/* Name: Basic full backup script Author: Faryl O'Neil Hoover - XTIVIA Date: 2/28/2021 Can be used in a SQL Server Agent job that runs daily, at minimum. */ -- Variables DECLARE @DBCount int SELECT @DBCount = count(*) from sys.databases; DECLARE @myCount int = 0; DECLARE @dbName nvarchar(max); DECLARE @SQL nvarchar(max); WHILE (@myCount <= @DBcount) -- Basic WHILE loop cycling through databases on instance BEGIN IF EXISTS -- Just in case databases are skipped (like tempdb, since it can't be backed up) (SELECT name FROM sys.databases WHERE database_id = @myCount AND name != 'tempdb' -- Can't back up tempdb AND state = 0 -- Make sure databases are online AND is_read_only = 0) -- Make sure databases aren't read-only BEGIN SELECT @dbName = name FROM sys.databases WHERE database_id = @myCount; -- Grab database name to plug into backup script SET @SQL = 'BACKUP DATABASE ' + @dbname + -- Database backup statement ' TO DISK = ''' + @dbName + '_' + -- Name is automatically plugged in CONVERT(char(8), getdate(), 112) + -- Date is automatically generated from GETDATE() '.BAK'' WITH COMPRESSION, CHECKSUM, STATS = 10'; PRINT @SQL; -- For general debugging EXEC sp_executesql @SQL; -- Backup statement is executed END SET @myCount = @mycount + 1 -- Increment the counter END /* Name: Basic log backup script Author: Faryl O'Neil Hoover - XTIVIA Date: 2/28/2021 Can be used in a SQL Server Agent job that runs hourly, for instance. */ -- Variables DECLARE @DBCount int SELECT @DBCount = count(*) from sys.databases; DECLARE @myCount int = 0; DECLARE @dbName nvarchar(max); DECLARE @SQL nvarchar(max); WHILE (@myCount <= @DBcount) --Basic WHILE statement for cycling through databases BEGIN IF EXISTS (SELECT name FROM sys.databases WHERE database_id = @myCount AND name != 'tempdb' AND recovery_model = 1 -- Main difference from full backup script; only grab databases we can take log backups for AND state = 0 -- Make sure databases are online AND is_read_only = 0) -- Make sure databases are not read-only BEGIN SELECT @dbName = name FROM sys.databases WHERE database_id = @myCount; SET @SQL = 'BACKUP LOG ' + @dbname + ' TO DISK = ''' + @dbName + '_LOG_' + CONVERT(char(8), getdate(), 112) + '_' + CONVERT(char(2), datepart(hour, getdate())) + '_' + -- Another main difference from full backup script: Automatically generate hour/minute for file name, since log backups should be taken at least hourly CONVERT (char(2), datepart(minute, getdate())) + '.TRN'' WITH COMPRESSION, CHECKSUM, STATS = 10'; PRINT @SQL; EXEC sp_executesql @SQL; END SET @myCount = @mycount + 1 END
One final note: Sometimes, “not enough backups” can turn into “too many backups”—on disk, that is. Depending on your individual circumstances (such as database size and data recovery objectives), you may only need to keep the most recent backups on disk for a quick and easy restore while putting your older backups into long-term storage, such as tape or Grandpa’s shed. Again, your mileage may vary (long-term storage may not even be necessary, depending on your environment), but it bears mentioning as uncontrolled backups can fill up disk space FAST. Regardless, make sure to keep an eye on your disk space and remove older backups when needed.
If you have more specific backup needs and you have nowhere else to turn, our VirtualDBA staff is always here to help! Making sure your data can be recovered in the event of a disaster is our number-one priority, so don’t take chances on irregular and unreliable backups! Let us optimize your environment so you’ll be prepared for anything that comes your way.