Shrink Transaction Log
At a company I worked, they were in the process of setting up ERP software that was bought by their management.
Regardless the quality (or lack thereof) of the software that was installed for use at the company, one of my duties was to care for the good maintenance of the SQL Servers.
Well, long story short, this ERP software that was installed at the company I worked for created a log of 30 GB for a database of 1 GB.
It was outrageous.
So in order to prevent it to grow further I created a job that shrink the log daily.
Although it is pretty straightforward to do this for a single database, I decided to raise the bar a bit and create the same procedure for every single database on all our servers.
How to do this? It’s a two steps procedure.
First I ran a query that creates the SQL commands to generate the procedures on every database on the server.
Then I create a job that will run on the server daily, just prior to the full database backup, to keep the log file small.
USE master
GO
SET NOCOUNT ON
--
-- Creates a cursor with all databases in the server
--
DECLARE curdb CURSOR FOR
SELECT dbid, name
FROM sysdatabases
WHERE DatabaseProperty(name, 'IsOffline') = 0
DECLARE @dbid int
,@dbname varchar(256)
,@name varchar(256)
,@union bit
,@strSQL varchar(8000)
,@pos int
SET @strSQL = ''
SET @union = 0
--
-- Get the name of log files for all databases
--
OPEN curdb
FETCH curdb into @dbid, @dbname
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF LEN(@strSQL) > 7000
BEGIN
SET @pos = Len(@strSQL) - CharIndex(char(10), reverse(@strSQL)) + 1
PRINT SubString(@strSQL, 1, @pos)
SET @strSQL = SubString(@strSQL, @pos, 1000)
END
SET @strSQL = @strSQL + char(13) + char(10) + 'USE ' + @dbname + char(13) + char(10)
SET @strSQL = @strSQL + 'GO' + char(13) + char(10)
SET @strSQL = @strSQL + char(13) + char(10)
SET @strSQL = @strSQL + 'IF EXISTS (SELECT * FROM sysobjects WHERE name = ''sp_shrinklogfile'' AND type = ''P'')' + char(13) + char(10)
SET @strSQL = @strSQL + ' DROP PROCEDURE dbo.sp_shrinklogfile' + char(13) + char(10)
SET @strSQL = @strSQL + 'GO' + char(13) + char(10)
SET @strSQL = @strSQL + char(13) + char(10)
SET @strSQL = @strSQL + Char(13) + Char(10) + 'CREATE PROCEDURE dbo.sp_shrinklogfile'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' @NewSize int'
SET @strSQL = @strSQL + Char(13) + Char(10) + 'AS'
SET @strSQL = @strSQL + Char(13) + Char(10) + 'BEGIN'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET NOCOUNT ON'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' DECLARE @MaxMinutes INT, @Factor FLOAT'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @MaxMinutes = 1'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @Factor = 0.95'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' DECLARE @LogicalFileName varchar(250)'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ,@MaxSize BIGINT'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ,@OriginalSize BIGINT'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ,@StringData VARCHAR(500)'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SELECT TOP 1'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' @LogicalFileName = RTRIM( [name] ),'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' @MaxSize = CASE [maxsize]'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' WHEN -1 THEN -1'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ELSE ((cast ([maxsize] as bigint) * 8))/1024'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' END'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' FROM sysfiles'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' WHERE [groupid] = 0'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ORDER '
SET @strSQL = @strSQL + Char(13) + Char(10) + ' BY [size] DESC'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' IF @MaxSize > 0 AND @NewSize > @MaxSize'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' BEGIN'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @NewSize = @MaxSize'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' END'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' IF ( OBJECT_ID(''[dbo].[DummyTrans]'') IS NOT NULL )'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' BEGIN'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' DROP TABLE [' + @dbname + '].dbo.[DummyTrans]'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' END'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' CREATE TABLE [' + @dbname + '].dbo.[DummyTrans]( [DummyColumn] CHAR(8000) NOT NULL )'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' DECLARE @Counter INT'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ,@MaxCount INT'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ,@StartTime DATETIME'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ,@TruncLog VARCHAR(500)'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' DBCC SHRINKFILE ( @LogicalFileName, @NewSize)'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @TruncLog = ''BACKUP LOG ['' + db_name() + ''] WITH TRUNCATE_ONLY'''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' EXEC (@TruncLog)'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' IF @OriginalSize / @Factor > 50000'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @MaxCount = 50000'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' ELSE'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @MaxCount = @OriginalSize * @Factor'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @Counter = 0'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @StartTime = GETDATE()'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' WHILE ((@MaxMinutes*60 > DATEDIFF(ss, @StartTime, GETDATE())) '
SET @strSQL = @strSQL + Char(13) + Char(10) + ' AND (@OriginalSize = (SELECT size FROM sysfiles WHERE name =@LogicalFileName)) '
SET @strSQL = @strSQL + Char(13) + Char(10) + ' AND ((@OriginalSize * 8 / 1024) > @NewSize))'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' BEGIN'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' WHILE (( @Counter < @MaxCount) '
SET @strSQL = @strSQL + Char(13) + Char(10) + ' AND ( @MaxMinutes*60 > DATEDIFF(ss, @StartTime, GETDATE())) '
SET @strSQL = @strSQL + Char(13) + Char(10) + ' AND ( @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)) '
SET @strSQL = @strSQL + Char(13) + Char(10) + ' AND (( @OriginalSize * 8 / 1024) > @NewSize))'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' BEGIN '
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' INSERT INTO [' + @dbname + '].dbo.DummyTrans VALUES (''Fill Log'')'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' DELETE FROM [' + @dbname + '].dbo.DummyTrans'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET @Counter = @Counter + 1'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' END'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' EXEC( @TruncLog )'
SET @strSQL = @strSQL + Char(13) + Char(10) + ' END'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' DROP TABLE [' + @dbname + '].dbo.DummyTrans'
SET @strSQL = @strSQL + Char(13) + Char(10) + ''
SET @strSQL = @strSQL + Char(13) + Char(10) + ' SET NOCOUNT OFF'
SET @strSQL = @strSQL + Char(13) + Char(10) + 'END'
SET @strSQL = @strSQL + Char(13) + Char(10) + 'GO'
FETCH curdb into @dbid, @dbname
END
--
-- Reopen the cursor
--
CLOSE curdb
OPEN curdb
--
-- Create the procedure at the master db
--
SET @strSQL = @strSQL + char(13) + char(10) + 'USE master' + char(13) + char(10)
SET @strSQL = @strSQL + 'GO' + char(13) + char(10)
SET @strSQL = @strSQL + char(13) + char(10)
SET @strSQL = @strSQL + 'IF EXISTS (SELECT * FROM sysobjects WHERE name = ''sp_shrink_all_logs'' AND type = ''P'')' + char(13) + char(10)
SET @strSQL = @strSQL + ' DROP PROCEDURE dbo.sp_shrink_all_logs' + char(13) + char(10)
SET @strSQL = @strSQL + 'GO' + char(13) + char(10)
SET @strSQL = @strSQL + char(13) + char(10)
SET @strSQL = @strSQL + 'CREATE PROCEDURE dbo.sp_shrink_all_logs' + char(13) + char(10)
SET @strSQL = @strSQL + ' @NewSize int = 20' + char(13) + char(10)
SET @strSQL = @strSQL + 'AS' + char(13) + char(10)
SET @strSQL = @strSQL + 'BEGIN' + char(13) + char(10)
FETCH curdb into @dbid, @dbname
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF LEN(@strSQL) > 7000
BEGIN
SET @pos = Len(@strSQL) - CharIndex(char(10), reverse(@strSQL)) + 1
PRINT SubString(@strSQL, 1, @pos)
SET @strSQL = SubString(@strSQL, @pos, 1000)
END
SET @strSQL = @strSQL + ' EXEC ' + left(@dbname + '..sp_shrinklogfile' + space(40), 40) + ' @NewSize' + char(13) + char(10)
FETCH curdb into @dbid, @dbname
END
SET @strSQL = @strSQL + 'END' + char(13) + char(10)
SET @strSQL = @strSQL + 'GO' + char(13) + char(10)
SET @strSQL = @strSQL + char(13) + char(10)
CLOSE curdb
DEALLOCATE curdb
PRINT @strSQL
SET NOCOUNT OFF
- Get link
- X
- Other Apps
Comments
Post a Comment