SISMON-SQL Server Express Automating Database Maintenance
SISMON-SQL Server Express Automating Database Maintenance
2013
Blumenau
http://www.sismon.info
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings
Automating Database maintenance in SQL 2005 Express Edition demonstrates a couple of different approaches to writing a maintenance utility that mimics some of the behavior of the sqlmaint utility that is included with SQL Server 2000. The SQL Server 2000s sqlmaint utility, which can be accessed command-line or through the SQL Enterprise Manager, is used to configure and run manual/automated SQL backup jobs. Depending on the default security or current configuration of the Surface Area Configuration (SAC), it may be necessary to adjust the SAC settings to install and run the expressmaint script. This script creates a stored procedure that provided the following operations:
Full Database Backup Differential Database Backup Log Backup Housekeeping of backup files Database Integrity Checks Database Index Rebuilds Database index Reorganization Report Creation
Once the expressmaint stored procedure has been installed, the Windows Scheduler can be used to automate backup jobs. A clean install of SQL Server 2005 Express required the following changes to the default settings of the SAC to run the expressmaint script: 1. Run SQL Server 2005 Surface Area Configuration
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings
2. Select Surface Area Configuration for Features 3. Enable OLE Automation by selecting OLE Automation for the Database Engine in the SQL Instance (default instance is SQLExpress).
4. Enable xp_cmdshell by selecting xp_cmdshell for the Database Engine in the SQL Instance (default instance is SQLExpress).
5. Press OK to accept the changes. 6. Close Run SQL Server 2005 Surface Area Configuration
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings
7.
Load the stored procedure (expressmaint.sql) into SQL Express using the sqlcmd.
You can copy the file SQL Server 2005 Express Backup Automation Script.sql located on the distribution disk and rename it expressmaint.sql or copy the SQL script code which starts on page 9 of this document and past it into an empty notepad file which can be saved as espressmaint.sql. A. B.
Select Start | Run and enter cmd.exe then press OK. A command window will be displayed. At the command prompt enter the following (assuming a named instance called SQLExpress): Sqlcmd -E -S .\SQLExpress -i c:\expressmaint.sql
8.
To perform a backup copy the expressmaint instructions to a SQL script file and execute the script via sqlcmd. sqlcmd -E -S.\SQLExpress -i"c:\backup scripts\userfullbackup.sql"
Where c:\backup scripts\userfullbackup.sql contains the expressmaint instructions to execute (See page 8 for expressmaint script syntax), examples follow: A. To perform a Full Database Backup of all user databases to c:\backups, verify the backups and report to c:\reports keeping backups for 1 week and reports for 1 week use the following script: exec expressmaint @database = 'ALL_USER', @optype = 'DB', @backupfldr = 'c:\backups', @reportfldr = 'c:\reports', @verify = 1, @dbretainunit = 'weeks', @dbretainval = 1, @rptretainunit = 'weeks', @rptretainval = 1, @report = 1 B. To perform a rebuilding of the indexes for the DB_ASTRA database and report to c:\reports keeping reports for 1 week use the following script: exec expressmaint @database = 'DB_ASTRA', @optype = 'REINDEX', @reportfldr = 'c:\reports', @rptretainunit = 'days', @rptretainval = 1, @report = 1 C. To use a single script and pass parameters to it for the type of task, the following script and sqlcmd would perform a Full Database Backup of all user databases to c:\backups, verify the backups and report to c:\reports keeping backups for 1 week and reports for 1 week: exec expressmaint @database = '$(DB)', @optype = 'DB', @backupfldr = '$(BACKUPFOLDER)', @reportfldr = 'c:\reports', @verify = 1, @dbretainunit = '$(DBRETAINUNIT)', @dbretainval = '$(DBRETAINVAL)', @rptretainunit = 'weeks', @rptretainval = 1, @report = 1 The sqlcmd would be as follows (no line breaks): sqlcmd -S .\SQLExpress -i"c:\backup scripts\userfullbackup.sql" -v DB="ALL_USER" -v BACKUPFOLDER="c:\backups" -v DBRETAINUNIT="weeks" -v DBRETAINVAL="1"
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings Scheduling Backups (Windows XP)
To schedule backups, use Windows Scheduled Tasks. 1. Open the Scheduled Tasks window by pressing the Start button, then selecting All Programs, Accessories, System Tools, Scheduled Tasks.
3. Press Next
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings
4. Press Browse and navigate to the folder containing sqlcmd.exe, select the file and press Open. The default installation folder is c:\Program Files\Microsoft SQL Server\90\Tools\Binn
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings
7. Edit the task, right-click the task name and select Properties. The run command on the Task tab will contain the following: "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE" A. Add a space after the closing quote and add the sqlcmd parameters. For example: "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE" -E -S.\SQLExpress -i"c:\userfullbackup.sql" B. Press OK to save and close the task. 8. Test the new task, right-click the task name (SQLdiag in this example) and select run.
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings
9. View the report file in the specified report folder. Verify the existence of the backup file in the specified folder. The example show below used the same folder for the backup and report files (c:\backup) and performed two full back ups on the DB_Astra database.
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings Expressmaint Script Syntax
Parameter @database Required
Y
Default
NONE
Description
The target database for the maintenance operation. Valid values are a single database name, ALL_USER which will process all user databases and ALL_SYSTEM which will process all system databases The type of maintenance operation to be performed. Valid values are DB - Full Database Backup DIFF - Differential Database Backup LOG - Log Backup CHECKDB - Database Integrity Check REINDEX - Rebuild all indexes
@optype
NONE
Specify additional backup options as documented in BOL for the BACKUP WITH command The base folder to write the backups to. Sub folders will be created for each database Indicates whether to verify the backup file. Valid values are 1 and 0 with 1 = TRUE and 0 = FALSE
NULL
Specify additional verify options as documented in BOL for the VERIFY WITH command The unit of measure for the @dbretainval parameter. Valid values are minutes, hours, days, weeks, months and copies. The combination of these two parameters determines how long or how many copies of old backup files are kept
NULL
The time period or number of copies of old backups to keep Indicates whether to produce a report of the maintenance carried out. Valid values are 1 and 0 with 1 = TRUE and 0 = FALSE
NULL
The folder where maintenance reports are written to if @report = 1 The unit of measure for the @rptretainval parameter. Valid values are minutes, hours, days, weeks, months and copies. The combination of these two parameters determines how long or how many copies of old reports are kept
NULL
@rptretainval @checkattrib
The time period or number of copies of old reports to keep Indicates whether to check the archive bit on a backup file before deleting it. This is a safety check to prevent deletion of files that have not been backed up onto tape. Valid values are 1 and 0 with 1 = TRUE and 0 = FALSE Indicates whether to delete old backups prior to doing the current backup. This is not advisable but can be useful if disk space is limited. Valid values are 1 and 0 with 1 = TRUE and 0 = FALSE Indicates whether print out debug information such as the commands generated and the contents of the temporary tables used in the procedure. Valid values are 1 and 0 with 1 = TRUE and 0 = FALSE
@delfirst
@debug
8 of 25
SQL Server 2005 Express Surface Area Configuration (SAC) expressmaint script settings expressmaint.sql Script Code
The expressmaint script code is included below. Copy everything after the separator to the end of the document and paste into a text file name expressmaint.sql to recreate the script file. Page headers and line numbers for the remainder of the document have been omitted for copying the script text.
use master GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[expressmaint]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[expressmaint] GO CREATE PROCEDURE ( @database @optype @backupwith @backupfldr @reportfldr @verify @verifywith @dbretainunit @dbretainval @report @rptretainunit @rptretainval @checkattrib @delfirst @debug ) AS /* expressmaint see Date 24/07/2004 */ SET SET NOCOUNT DATEFORMAT ON YMD http://www.sqldbatips.com/showarticle.asp?ID=27 Author Jasper Smith Notes Initial release for documentation expressmaint sysname, varchar(7), varchar(500) = NULL, varchar(200) = NULL, varchar(200) = NULL, bit = 1, varchar(500) = NULL, varchar(10) = NULL, int = 1, bit = 1, varchar(10) = NULL, int = 1, bit = 0, bit = 0, bit = 0 ---------------database name | ALL_USER | ALL_SYSTEM LOG | DB | DIFF | REINDEX | REORG | CHECKDB additional backup options folder to write backup to folder to write text report verify backup additional verify options minutes | hours | days | weeks | months | copies specifies how many retainunits to keep backup flag to indicate whether to generate report minutes | hours | days | weeks | months | copies specifies how many retainunits to keep reports check if archive bit is cleared before deleting delete before backup (handy if space issues) print commands to be executed
/************************ VARIABLE DECLARATION ************************/ DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE @fso @file @reportfilename @backupfilename @delfilename @cmd @backupfldrorig @databaseorig @table @exists @err @start @finish @runtime @output @errormsg @datepart @execmd @delcmd @exemsg @filecount @delcount @hr int int varchar(500) varchar(500) varchar(500) varchar(650) varchar(200) sysname nvarchar(600) varchar(5) int datetime datetime datetime varchar(200) varchar(210) nchar(2) nvarchar(1000) nvarchar(1000) varchar(8000) int int int
; ; ;
0 0 0
; ; ; ; ; ; ; ; ;
= = = = = = = =
0 0 0 0 0 SUSER_SNAME() GETDATE() 1
IF RIGHT(@backupfldr,1)<>'\' SET @backupfldr = @backupfldr + '\' SET @backupfldrorig = @backupfldr SET @databaseorig = @database CREATE CREATE CREATE TABLE TABLE TABLE #files(filename varchar(255)) #exists(exist int,isdir int,parent #databases(dbname sysname) int)
***********************************/ IF @report = 1 BEGIN EXEC @hr=sp_OACreate 'Scripting.FileSystemObject',@fso OUT IF @hr <> 0 BEGIN EXEC sp_OAGetErrorInfo @fso RAISERROR('Error creating File System Object',16,1) SET @ret = 1 GOTO CLEANUP END END
/************************ CHECK INPUT
************************/ -- check SQL2005 or higher IF (select SUBSTRING(@@version,(CHARINDEX(' ',@@version)+2),1))<9 BEGIN RAISERROR('SQL2005 or higher is required for sp_expressmaint',16,1) SET @ret = 1 GOTO CLEANUP END -- check sysadmin IF IS_SRVROLEMEMBER('sysadmin') = 0 BEGIN RAISERROR('The current user %s is not a member of the sysadmin role',16,1,@user) SET @ret = 1 GOTO CLEANUP END -- check database exists and is online IF @database NOT IN ('ALL_USER','ALL_SYSTEM') BEGIN IF (DB_ID(@database) IS NULL) OR ((select state from sys.databases where name = @database) <>0) BEGIN RAISERROR('Database %s is invalid or database status is not ONLINE',16,1,@database) SET @ret = 1 GOTO CLEANUP END END -- check @optype is valid IF UPPER(@optype) NOT IN ('LOG','DB','DIFF','REINDEX','REORG','CHECKDB') BEGIN RAISERROR('%s is not a valid option for @optype',16,1,@optype) SET @ret = 1 GOTO CLEANUP END -- check recovery mode is correct if trying log backup IF @database NOT IN ('ALL_USER','ALL_SYSTEM') BEGIN
IF (@optype = 'LOG' and ((select recovery_model from sys.databases where name = @database) = 3)) BEGIN RAISERROR('%s is not a valid option for database %s because it is in SIMPLE recovery mode',16,1,@optype,@database) SET @ret = 1 GOTO CLEANUP END END -- no log backups for system databases IF @database = 'ALL_SYSTEM' BEGIN IF @optype = 'LOG' BEGIN RAISERROR('%s is not a valid option for the option ALL_SYSTEM',16,1,@optype) SET @ret = 1 GOTO CLEANUP END END -- check that @backupfldr exists on the server IF @optype NOT IN ('REINDEX','CHECKDB','REORG') BEGIN IF @report = 1 BEGIN EXEC sp_OAMethod @fso,'FolderExists',@exists OUT,@backupfldr IF @exists <> 'True' BEGIN RAISERROR('The folder %s does not exist on this server',16,1,@backupfldr) SET @ret = 1 GOTO CLEANUP
END END ELSE BEGIN
INSERT BEGIN
#exists
RAISERROR('The folder %s does not exist on this server',16,1,@backupfldr) SET @ret = 1 GOTO CLEANUP
END END
END -- check that @reportfldr exists on the server IF @reportfldr IS NOT NULL or @report = 1 BEGIN IF @report = 1 BEGIN EXEC sp_OAMethod @fso,'FolderExists',@exists OUT,@reportfldr IF @exists <> 'True' BEGIN RAISERROR('The folder %s does not exist on this server',16,1,@reportfldr) SET @ret = 1 GOTO CLEANUP
END END ELSE BEGIN DELETE #exists INSERT #exists EXEC master.dbo.xp_fileexist @reportfldr IF (SELECT MAX(isdir) FROM #exists)<>1
BEGIN RAISERROR('The folder %s does not exist on this server',16,1,@reportfldr) SET @ret = 1 GOTO CLEANUP
END END
END -- check @dbretainunit is a vaild value IF @optype NOT IN ('REINDEX','CHECKDB','REORG') BEGIN IF UPPER(@dbretainunit) NOT IN ('MINUTES','HOURS','DAYS','WEEKS','MONTHS','COPIES') BEGIN
RAISERROR('%s is not a valid value for @dbretainunit (''minutes | hours | days | weeks | months | copies'')',16,1,@dbretainunit) SET @ret = 1 GOTO CLEANUP END END --check @dbretainval is a vaild value IF @dbretainval<1 BEGIN RAISERROR('%i is not a valid value for @dbretainval (must be >0)',16,1,@dbretainval) SET @ret = 1 GOTO CLEANUP END -- check @rptretainunit is a vaild value if present IF UPPER(@rptretainunit) NOT IN ('MINUTES','HOURS','DAYS','WEEKS','MONTHS','COPIES') and @rptretainunit IS NOT NULL BEGIN RAISERROR('%s is not a valid value for @rptretainunit (''minutes | hours | days | weeks | months | copies'')',16,1,@rptretainunit) SET @ret = 1 GOTO CLEANUP END --check @rptretainval is a vaild value IF @rptretainval<1 BEGIN RAISERROR('%i is not a valid value for @rptretainval (must be >0)',16,1,@rptretainval) SET @ret = 1 GOTO CLEANUP END /*********************************** list of databases to process ************************************/ IF @database IN ('ALL_USER','ALL_SYSTEM') BEGIN IF @database = 'ALL_USER' INSERT #databases(dbname) SELECT [name] from sys.databases where database_id AND (@optype <> 'LOG' OR recovery_model <> '3') ELSE INSERT #databases(dbname) SELECT [name] from sys.databases where database_id END ELSE INSERT #databases(dbname) SELECT @database /*********************************** INITIALIZE REPORT IF @report = 1 ************************************/ -- generate report filename SELECT @reportfilename = @reportfldr + REPLACE(@database,' ','_') + CASE WHEN UPPER(@optype) = 'DB' THEN '_FullDBBackup_report_' WHEN UPPER(@optype) = 'DIFF' THEN '_DiffDBBackup_report_' WHEN UPPER(@optype) = 'LOG' THEN '_LogBackup_report_' WHEN UPPER(@optype) = 'REINDEX' THEN '_Reindex_report_' WHEN UPPER(@optype) = 'REORG' THEN '_Reorg_report_' WHEN UPPER(@optype) = 'CHECKDB' THEN '_CheckDB_report_' END -IF + if @jobstart no report = + 0 '.txt' set @reportfilename @reportfilename = to NULL NULL SET just
>
in
(1,3,4)
@report
'
ISNULL(@reportfilename,'NULL')
IF @report = 1 BEGIN -- create report file EXEC @hr=sp_OAMethod @fso, 'CreateTextFile',@file OUT, @reportfilename IF (@hr <> 0)
BEGIN EXEC sp_OAGetErrorInfo @fso RAISERROR('Error creating log file',16,1) SET @ret = 1 GOTO CLEANUP END ELSE -- set global flag to indicate we have created a report file SET @filecrt = 1 -- write header EXEC sp_OAMethod
SET @output =
@file,'WriteLine',NULL,''
utility, Logged on to SQL Server [' + @@SERVERNAME + '] as ' + '[' + @user +
'Expressmaint
']' IF @debug = 1 PRINT @output EXEC sp_OAMethod @file,'WriteLine',NULL,@output IF UPPER(@optype) BEGIN SET @output = END IF UPPER(@optype) BEGIN SET @output = END IF UPPER(@optype) BEGIN SET @output = END NOT IN ('REINDEX','CHECKDB','REORG') backup on ' + convert(varchar(25),getdate(),100)
'Starting =
'Starting IN
'Starting
IF @debug = 1 PRINT @output EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END
/************************ BACKUP ACTIONS
-- if @delfirst = 1 we need to delete prior backups that qualify IF @delfirst = 1 GOTO DELFIRST -- this label is so that we can return here after deleting files if @delfirst = 1 DOBACKUP: DECLARE dcur CURSOR LOCAL FAST_FORWARD FOR SELECT dbname FROM #databases ORDER OPEN dcur FETCH NEXT FROM dcur into @database WHILE @@FETCH_STATUS=0 BEGIN
-- set backup start time SET @start = GETDATE()
BY
dbname
-- write to text report IF @report = 1 BEGIN SET @output = '[' + CAST(@stage as varchar(10)) + '] Database ' + @database + ': ' + CASE WHEN UPPER(@optype) = 'DB' THEN 'Full Backup ' WHEN UPPER(@optype) = 'DIFF' THEN 'Differential Backup ' WHEN UPPER(@optype) = 'LOG' THEN 'Log Backup ' END + 'starting at ' + CONVERT(varchar(25),@start,100) IF @debug = 1 PRINT @output EXEC sp_OAMethod @file,'WriteLine',NULL,@output END -SET
backup
@execmd
subfolder
= 'IF NOT EXIST "' + @backupfldrorig + @database + '\" MKDIR "' + @backupfldrorig + @database
'\"' EXEC master.dbo.xp_cmdshell @execmd,no_output SET @backupfldr = @backupfldrorig + @database SELECT @backupfilename = @backupfldr +
'\' ','_') +
REPLACE(@database,'
WHEN UPPER(@optype) = 'DB' THEN '_FullDBBackup_' WHEN UPPER(@optype) = 'DIFF' THEN '_DiffDBBackup_' WHEN UPPER(@optype) = 'LOG' THEN '_LogBackup_' + @jobstart + WHEN UPPER(@optype) = 'LOG' THEN '.TRN' ELSE '.BAK' END
SET @execmd = N'BACKUP DATABASE [' + @database + '] TO DISK = ''' + @backupfilename + '''' + CASE WHEN @backupwith IS NULL THEN '' ELSE (' WITH ' + @backupwith) END BEGIN TRY
EXEC(@execmd) END TRY BEGIN CATCH -- backup failure SELECT @err = @@ERROR,@ret =
SELECT @errormsg = 'Full backup of
@err
database ' + @database + ' failed with error : ' + CAST(@err as
varchar(10)) SET @output = SPACE(4) + '*** ' + @errormsg + ' ***' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output SET @output = SPACE(4) + 'Refer to SQL Error Log and NT Event Log for further details' EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END
CLOSE dcur DEALLOCATE dcur GOTO CLEANUP
END
CATCH
-- backup success SET @finish = GETDATE() SET @output = SPACE(4) + 'Database backed up to ' + @backupfilename IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END --calculate backup runtime SET @runtime = (@finish - @start) SET @output = SPACE(4) + 'Full database backup completed in ' + CAST(DATEPART(hh,@runtime) as varchar(2)) + ' hour(s) ' + CAST(DATEPART(mi,@runtime) as varchar(2)) + ' min(s) ' + CAST(DATEPART(ss,@runtime) as varchar(2)) + ' second(s)' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END END /************************ DIFFERENTIAL BACKUP ************************/ IF UPPER(@optype) BEGIN = 'DIFF'
SET @execmd = N'BACKUP DATABASE [' + @database + '] TO DISK = ''' + @backupfilename + ''' WITH DIFFERENTIAL' + CASE WHEN @backupwith IS NULL THEN '' ELSE (' BEGIN TRY
'
@backupwith)
END
--
backup
failure
SELECT @err = @@ERROR,@ret = @err SELECT @errormsg = 'Differential backup of database ' + @database + ' failed with error : ' + CAST(@err as varchar(10)) SET @output = SPACE(4) + '*** ' + @errormsg + ' ***' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output SET @output = SPACE(4) + 'Refer to SQL Error Log and NT Event Log for further details' EXEC sp_OAMethod @file,'WriteLine',NULL,@output END
CLOSE dcur DEALLOCATE dcur GOTO CLEANUP
END
CATCH
-- backup success SET @finish = GETDATE() SET @output = SPACE(4) + 'Database backed up to ' + @backupfilename IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END --calculate backup runtime SET @runtime = (@finish - @start) SET @output = SPACE(4) + 'Differential database backup completed in + CAST(DATEPART(hh,@runtime) as varchar(2)) + ' hour(s) ' + CAST(DATEPART(mi,@runtime) as varchar(2)) + ' min(s) ' + CAST(DATEPART(ss,@runtime) as varchar(2)) + ' second(s)' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END END /************************ LOG BACKUP ************************/ IF UPPER(@optype) BEGIN = 'LOG'
'
SET @execmd = N'BACKUP LOG [' + @database + '] TO DISK = ''' + @backupfilename + '''' + CASE WHEN @backupwith IS NULL THEN '' ELSE (' WITH ' + @backupwith) END BEGIN TRY
--
backup =
= 'Log
failure =
of
@err
@errormsg
@@ERROR,@ret
backup
@err
database ' + @database + ' failed with error : ' + CAST(@err as
varchar(10)) SET @output = SPACE(4) + '*** ' + @errormsg + ' ***' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output SET @output = SPACE(4) + 'Refer to SQL Error Log and NT Event Log for further details' EXEC sp_OAMethod @file,'WriteLine',NULL,@output END
CLOSE dcur DEALLOCATE dcur GOTO CLEANUP
END
CATCH
-- backup success SET @finish = GETDATE() SET @output = SPACE(4) + 'Log backed up to ' + @backupfilename IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END --calculate backup runtime SET @runtime = (@finish - @start) SET @output = SPACE(4) + 'Log backup completed in + CAST(DATEPART(hh,@runtime) as varchar(2)) + CAST(DATEPART(mi,@runtime) as varchar(2)) + CAST(DATEPART(ss,@runtime) as varchar(2)) IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END END SET FETCH END CLOSE dcur DEALLOCATE dcur
/************************ VERIFY BACKUP
' + + +
@stage NEXT
(@stage dcur
1) @database
FROM
into
DECLARE dcur CURSOR LOCAL FAST_FORWARD FOR SELECT dbname FROM #databases ORDER OPEN dcur FETCH NEXT FROM dcur into @database WHILE @@FETCH_STATUS=0 BEGIN
BY
dbname
SELECT @backupfilename = @backupfldrorig + @database + '\' + REPLACE(@database,' ','_') + CASE WHEN UPPER(@optype) = 'DB' THEN '_FullDBBackup_'
WHEN UPPER(@optype) = 'DIFF' THEN '_DiffDBBackup_' WHEN UPPER(@optype) = 'LOG' THEN '_LogBackup_'
'LOG'
THEN
'.TRN'
ELSE
'.BAK'
END
File...' IF @debug = 1 PRINT @output EXEC sp_OAMethod @file,'WriteLine',NULL,@output END SET BEGIN @execmd TRY = N'RESTORE
WHEN
VERIFYONLY
IS
FROM
NULL
DISK
THEN
=
''
'''
ELSE
@backupfilename
(' WITH ' +
''''
+
END
CASE
@verifywith
@verifywith)
SET
@errormsg
'Verify
of
'
@backupfilename
'
failed
with
Native
Error
'
CAST(@err
as
varchar(10)) SET @output = SPACE(4) + '*** ' + @errormsg + IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END
CLOSE dcur DEALLOCATE dcur GOTO CLEANUP
'
***'
END
CATCH
-- verify success SET @finish = GETDATE() SET @output = SPACE(4) + 'Backup file ' + @backupfilename + ' verified' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod END
@file,'WriteLine',NULL,@output
--calculate verify runtime SET @runtime = (@finish - @start) SET @output = SPACE(4) + 'Verify backup completed in + CAST(DATEPART(hh,@runtime) as varchar(2)) + + CAST(DATEPART(mi,@runtime) as varchar(2)) + + CAST(DATEPART(ss,@runtime) as varchar(2)) + IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END SET @stage FETCH NEXT END = (@stage FROM dcur + 1) into @database
CLOSE dcur DEALLOCATE dcur END /************************ DELETE OLD FILES ************************/ -- we have already deleted files so skip to the end IF @delfirst = 1 GOTO CLEANUP -- this label is so that we can delete files prior to backup if @delfirst = 1 DELFIRST:
/************************ DELETE OLD BACKUPS
************************/ SET @datepart = CASE WHEN UPPER(@dbretainunit) = 'MINUTES' THEN N'mi' WHEN UPPER(@dbretainunit) = 'HOURS' THEN N'hh' WHEN UPPER(@dbretainunit) = 'DAYS' THEN N'dd' WHEN UPPER(@dbretainunit) = 'WEEKS' THEN N'ww' WHEN UPPER(@dbretainunit) = 'MONTHS' THEN N'yy' @debug = 1 PRINT '@datepart for backups = ' + @datepart
END IF
-- write to text report IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,'' END SET @output = '[' + CAST(@stage as varchar(10)) + '] Delete Old Backup Files...' IF @debug = 1 PRINT @output IF @report = 1 BEGIN
EXEC END
sp_OAMethod
@file,'WriteLine',NULL,@output
DECLARE dcur CURSOR LOCAL FAST_FORWARD FOR SELECT dbname FROM #databases ORDER OPEN dcur FETCH NEXT FROM dcur into @database WHILE @@FETCH_STATUS=0 BEGIN
BY
dbname
SET @backupfldr = + @backupfldrorig + @database + '\' SELECT @backupfilename = @backupfldr + REPLACE(@database,' ','_') CASE WHEN UPPER(@optype) = 'DB' THEN '_FullDBBackup_' WHEN UPPER(@optype) = 'DIFF' THEN '_DiffDBBackup_' WHEN UPPER(@optype) = 'LOG' THEN '_LogBackup_' END + @jobstart + CASE WHEN UPPER(@optype) = 'LOG' THEN '.TRN' ELSE '.BAK' END
-- load files in @backupfldr IF @checkattrib = 1
SET @cmd = 'dir /B /A-D-A /OD "' + @backupfldr + REPLACE(@database,' ','_') + CASE WHEN UPPER(@optype) = 'DB' THEN '_FullDBBackup_' WHEN UPPER(@optype) = 'DIFF' THEN '_DiffDBBackup_' WHEN UPPER(@optype) = 'LOG' THEN '_LogBackup_' END + '*' + CASE WHEN UPPER(@optype) = 'LOG' THEN '.TRN' ELSE '.BAK' END + '"' ELSE SET @cmd = 'dir /B /A-D /OD "' + @backupfldr + REPLACE(@database,' ','_') + CASE WHEN UPPER(@optype) = 'DB' THEN '_FullDBBackup_' WHEN UPPER(@optype) = 'DIFF' THEN '_DiffDBBackup_' WHEN UPPER(@optype) = 'LOG' THEN '_LogBackup_' END + '*' + CASE WHEN UPPER(@optype) = 'LOG' THEN '.TRN' ELSE '.BAK' END + '"' IF @debug = 1 PRINT '@cmd = ' + @cmd
DELETE #files INSERT #files EXEC master.dbo.xp_cmdshell @cmd DELETE #files WHERE filename IS NULL or filename ISNULL(REPLACE(@backupfilename,@backupfldr,''),'nothing') IF @debug = 1 SELECT * FROM #files
-- get count of files that match pattern SELECT @filecount = COUNT(*) from #files
-- remove files that don't meet retention criteria pattern IF UPPER(@dbretainunit) <> 'COPIES' BEGIN
IF @filecount>0 BEGIN
if there
SET @delcmd = N'DELETE #files WHERE DATEADD(' + @datepart + N',' + CAST(@dbretainval as nvarchar(10)) + N',' +
'CONVERT(datetime,(SUBSTRING(SUBSTRING(filename,((LEN(filename)CHARINDEX(''_'',REVERSE(filename)))+2),12),7,2) +''/''
IF @debug = 1 PRINT '@delcmd=' + @delcmd EXEC master.dbo.sp_executesql @delcmd SELECT @delcount = COUNT(*) from #files END ELSE BEGIN SELECT @delcount = 0 END END ELSE -- number of copies not date based (include current backup that's not in #files) BEGIN
IF @filecount>0 BEGIN
N'DELETE
#files
WHERE
filename
IN(SELECT
TOP
'
CAST((@dbretainval-1)
as
nvarchar(10))
substring(filename,((len(filename)+2)-charindex(''_'',reverse(filename))),12) DESC)' IF @debug = 1 PRINT '@delcmd=' + @delcmd EXEC master.dbo.sp_executesql @delcmd END SELECT END ELSE BEGIN SELECT END END IF @debug = @delcount = COUNT(*) from #files
@delcount
'@delcount
'
STR(@delcount)
-- if there are any matching files IF @filecount>0 BEGIN -- are there any files that need deleting IF @delcount>0 BEGIN DECLARE FCUR CURSOR FORWARD_ONLY FOR SELECT * FROM #files OPEN FCUR FETCH NEXT FROM FCUR INTO @delfilename WHILE @@FETCH_STATUS=0 BEGIN SET @cmd = 'DEL /Q "' + @backupfldr + @delfilename + '"' EXEC @cmdret = master.dbo.xp_cmdshell @cmd,no_output -- log failure to delete but don't abort procedure IF @cmdret<>0 BEGIN
SET @output = SPACE(4) + '*** Error: Failed to delete file ' + @backupfldr + @delfilename + '
***' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END SELECT @delbkflag = 1 , @cmdret = 0, @delcount = (@delcount-1) END ELSE BEGIN SET @output = SPACE(4) + 'Deleted file ' + @backupfldr + @delfilename IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END END FETCH NEXT FROM END CLOSE FCUR DEALLOCATE FCUR END END -- write to text report SET @output = SPACE(4) + CAST(@delcount as varchar(10)) + ' file(s) deleted.' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END FETCH END NEXT FROM dcur into @database FCUR INTO @delfilename
CLOSE dcur DEALLOCATE dcur -- clear temporary table and variables DELETE #files SET @cmd = '' SET @delcmd = '' SET @delfilename = '' SET @datepart = '' SET @filecount = 0 SET @delcount = 0 SET @cmdret = 0 SET @stage = @stage + 1
/************************ DELETE OLD REPORTS
************************/ DELREPORTS: IF @rptretainunit IS NOT NULL BEGIN SET @datepart = CASE WHEN UPPER(@rptretainunit) = 'MINUTES' THEN N'mi' WHEN UPPER(@rptretainunit) = 'HOURS' THEN N'hh' WHEN UPPER(@rptretainunit) = 'DAYS' THEN N'dd' WHEN UPPER(@rptretainunit) = 'WEEKS' THEN N'ww' WHEN UPPER(@rptretainunit) = 'MONTHS' THEN N'yy' END IF @debug = 1 PRINT '@datepart for reports = ' + @datepart
-- write to text report SET @output = '[' + CAST(@stage as varchar(10)) + '] Delete Old Report Files...' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END -- load files in @reportfldr SET @cmd = 'dir /B /A-D /OD "' + @reportfldr + REPLACE(@databaseorig,' ','_') + CASE WHEN UPPER(@optype) = 'DB' THEN '_FullDBBackup_report_' WHEN UPPER(@optype) = 'DIFF' THEN '_DiffDBBackup_report_' WHEN UPPER(@optype) = 'REINDEX' THEN '_Reindex_report_' WHEN UPPER(@optype) = 'CHECKDB' THEN '_CheckDB_report_' WHEN UPPER(@optype) = 'REORG' THEN '_Reorg_report_' WHEN UPPER(@optype) = 'LOG' THEN '_LogBackup_report_' END + '*.txt"' IF @debug = 1 PRINT '@cmd = ' + @cmd @cmd
INSERT DELETE IF
#files #files = 1
@debug
-- get count of files that match pattern SELECT @filecount = COUNT(*) from #files
-- remove files that don't meet retention criteria if there are any files that match pattern IF UPPER(@rptretainunit) <> 'COPIES' BEGIN
IF @filecount>0 BEGIN
SET @delcmd = N'DELETE #files WHERE DATEADD(' + @datepart + N',' + CAST(@rptretainval as nvarchar(10))
N','
+
+ SUBSTRING(SUBSTRING(filename,((LEN(filename)-CHARINDEX(''_'',REVERSE(filename)))+2),12),5,2) SUBSTRING(SUBSTRING(filename,((LEN(filename)-CHARINDEX(''_'',REVERSE(filename)))+2),12),1,4) SUBSTRING(SUBSTRING(filename,((LEN(filename)-CHARINDEX(''_'',REVERSE(filename)))+2),12),9,2)
+''
''
+
+'':''
IF @debug = 1 PRINT '@delcmd=' + @delcmd EXEC master.dbo.sp_executesql @delcmd SELECT END ELSE BEGIN SELECT END @delcount = COUNT(*) from #files
@delcount
SET @delcmd = N'DELETE #files WHERE filename IN(SELECT TOP ' + CAST(@rptretainval as nvarchar(10)) + N' filename FROM #files ORDER BY substring(filename,((len(filename)+2)charindex(''_'',reverse(filename))),12) DESC)' IF @debug = 1 PRINT '@delcmd=' + @delcmd EXEC master.dbo.sp_executesql @delcmd SELECT END ELSE BEGIN SELECT END END IF @debug = 1 PRINT STR(@delcount) @delcount = COUNT(*) from #files
@delcount
-- if there are any matching files IF @filecount>0 BEGIN -- are there any files that need deleting IF @delcount>0 BEGIN DECLARE FCUR CURSOR FORWARD_ONLY FOR SELECT * FROM #files OPEN FCUR FETCH NEXT FROM FCUR INTO @delfilename WHILE @@FETCH_STATUS=0 BEGIN
SET @cmd = 'DEL /Q "' + @reportfldr + @delfilename + '"' EXEC @cmdret = master.dbo.xp_cmdshell @cmd,no_output
***' IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END SELECT @delrptflag = 1 , @cmdret = 0, @delcount
END BEGIN
(@delcount-1)
SET @output = SPACE(4) + 'Deleted file ' + @reportfldr + @delfilename IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END END FETCH NEXT FROM END CLOSE FCUR DEALLOCATE FCUR END END FCUR INTO @delfilename
-- write to text report SET @output = SPACE(4) + CAST(@delcount as varchar(10)) + ' file(s) deleted.' IF @debug = 1 PRINT @output IF @report = 1 BEGIN
EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,''
END -- update stage SET @stage = @stage + 1 END -- if we got here due to @delfirst = 1 go back and do the backups IF @delfirst = 1 GOTO DOBACKUP ELSE GOTO CLEANUP /************************ CHECKDB ************************/ CHECK_DB: IF @optype BEGIN = 'CHECKDB'
DECLARE dcur CURSOR LOCAL FAST_FORWARD FOR SELECT dbname FROM #databases ORDER OPEN dcur FETCH NEXT FROM dcur into @database WHILE @@FETCH_STATUS=0 BEGIN
BY
dbname
-- write to text report IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,'' SET @output = '[' + CAST(@stage as varchar(10)) + '] Database ' + @database + ': Check Data and Index Linkage...' IF @debug = 1 PRINT @output EXEC sp_OAMethod @file,'WriteLine',NULL,@output END
-- set backup start time SET @start = GETDATE()
WITH
NO_INFOMSGS'
@err
=
=
@@ERROR,@ret
'CheckDB of '
=
+
@err
@database + ' failed with Native Error : ' + CAST(@err as
@errormsg
varchar(10)) SET @output = SPACE(4) + '*** ' + @errormsg + PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END
CLOSE dcur DEALLOCATE dcur GOTO CLEANUP
'
***'
END SET
--calculate checkdb runtime SET @runtime = (@finish - @start) SET @output = SPACE(4) + 'CheckDB
completed
in
'
+ CAST(DATEPART(hh,@runtime) as varchar(2)) + CAST(DATEPART(mi,@runtime) as varchar(2)) + CAST(DATEPART(ss,@runtime) as varchar(2)) IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END SET @stage = (@stage + 1) FETCH NEXT FROM dcur into @database END CLOSE dcur DEALLOCATE dcur
-- delete reports IF @report = 1 BEGIN
+ + +
@file,'WriteLine',NULL,''
DECLARE dcur CURSOR LOCAL FAST_FORWARD FOR SELECT dbname FROM #databases ORDER OPEN dcur FETCH NEXT FROM dcur into @database WHILE @@FETCH_STATUS=0 BEGIN -- write to text report IF @report = 1 BEGIN
EXEC sp_OAMethod @file,'WriteLine',NULL,'' IF @optype = 'REINDEX'
BY
dbname
SET @output = '[' + CAST(@stage as varchar(10)) + '] Database ' + @database + ': Index Rebuild (using original fillfactor)...' ELSE
SET @output = '[' + CAST(@stage as varchar(10)) + '] Database ' + @database + ': Index
Reorganize...' IF @debug = 1 PRINT @output EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END -- set start SET @start = time GETDATE()
-- all user tables CREATE TABLE #tables(tablename sysname) EXEC(N'INSERT #tables(tablename) SELECT DISTINCT(''['' + s.[name] + ''].['' + t.[name] + '']'') FROM [' + @database + N'].sys.tables t ' + N'JOIN [' + @database + N'].sys.schemas s on t.schema_id=s.schema_id ' + N'JOIN [' + @database + N'].sys.indexes i on t.object_id=i.object_id ' + N'WHERE t.is_ms_shipped = 0 AND i.type>0') DECLARE tcur CURSOR LOCAL FAST_FORWARD FOR SELECT tablename FROM #tables ORDER OPEN tcur FETCH NEXT FROM tcur INTO @table WHILE @@FETCH_STATUS = 0 BEGIN IF @report = BEGIN IF @optype 1 = 'REINDEX' BY tablename
@output @output
= =
SPACE(4) SPACE(4)
+ +
N'Rebuilding N'Reorganizing
indexes indexes
for for
table table
' '
+ +
@table @table
sp_OAMethod
@file,'WriteLine',NULL,@output
@optype = 'REINDEX' SET @execmd = N'ALTER INDEX ALL ON [' + @database + N'].' + @table + N' REBUILD' ELSE
SET @execmd = N'ALTER INDEX ALL ON [' + @database + N'].' + @table + N' REORGANIZE'
IF
@debug TRY
'Reindex
Command
'
@execmd
BEGIN
EXEC(@execmd) END TRY BEGIN CATCH SELECT @err = @@ERROR,@ret = @err SET @errormsg = 'Rebuild of indexes on [' + @database + N'].' + @table + ' failed with Native Error : ' + CAST(@err as varchar(10)) SET @output = SPACE(4) + '*** ' + @errormsg + ' ***' PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,@output END
CLOSE tcur DEALLOCATE tcur DROP TABLE #tables GOTO CLEANUP
--calculate runtime SET @runtime = (@finish - @start) SET @output = SPACE(4) + 'Index maintenance completed + CAST(DATEPART(hh,@runtime) as varchar(2)) + + CAST(DATEPART(mi,@runtime) as varchar(2)) + + CAST(DATEPART(ss,@runtime) as varchar(2)) + IF @debug = 1 PRINT @output IF @report = 1 BEGIN EXEC sp_OAMethod @file,'WriteLine',NULL,'' EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,'' END DROP TABLE #tables = (@stage FROM dcur + 1) into @database
CLEANUP: DROP DROP DROP TABLE TABLE TABLE #files #exists #databases
-- if we encountered errors deleting old backups return failure IF @delbkflag<>0 BEGIN SET @errormsg = 'Expressmaint encountered errors deleting old backup files' + CHAR(13) + CASE WHEN @report = 1 THEN ('Please see ' + @reportfilename + CHAR(13) + ' for further details') ELSE '' END
RAISERROR(@errormsg,16,1) SET @ret = 1
END -- if we encountered errors deleting old reports return failure IF (@delrptflag<>0 AND @delbkflag = 0) BEGIN SET @errormsg = 'Expressmaint encountered errors deleting old report files' + CHAR(13) + CASE WHEN @report = 1 THEN ('Please see ' + @reportfilename + CHAR(13) + ' for further details') ELSE '' END
RAISERROR(@errormsg,16,1) SET @ret = 1
END -- if we created a file make sure we write trailer and destroy object IF @filecrt = 1 BEGIN -- write final part of report EXEC sp_OAMethod @file,'WriteLine',NULL,'' SET @output = 'Expressmaint processing finished at ' + CONVERT(varchar(25),GETDATE(),100) + ' (Return Code : ' + CAST(@ret as varchar(10)) + ')' IF @debug = 1 PRINT @output
EXEC sp_OAMethod @file,'WriteLine',NULL,@output EXEC sp_OAMethod @file,'WriteLine',NULL,''
-- destroy file object EXEC @hr=sp_OADestroy @file IF @hr <> 0 EXEC sp_OAGetErrorInfo END IF @report = 1 BEGIN EXEC @hr=sp_OADestroy @fso IF @hr <> 0 EXEC sp_OAGetErrorInfo END RETURN GO @ret
@file
@fso