Thursday, June 21, 2012

Shrink all SQL Server databases transaction log files

PROBLEM:
You want to shrink all SQL Server databases transaction log files to clean up some space

SOLUTION:
Use the following script to shrink all databases transaction log files. You can use it also as a maintenance job using SQL Server Agent

DECLARE @Log_name VARCHAR(1000)
DECLARE @Db_name VARCHAR(1000)
DECLARE @Recovery_model_desc VARCHAR(1000)
DECLARE @SQL nvarchar(2000)
DECLARE @ParmDefinition nvarchar(1000)
DECLARE @SizeAfter int

DECLARE db_cursor CURSOR FOR
SELECT
       F.NAME AS [LOG_NAME],
       DB.NAME AS [DB_NAME],
       DB.RECOVERY_MODEL_DESC AS [RECOVERY_MODEL_DESC]
FROM
       MASTER.SYS.MASTER_FILES F INNER JOIN MASTER.SYS.DATABASES DB
       ON DB.DATABASE_ID = F.DATABASE_ID
WHERE F.FILE_ID=2 AND DB.NAME <> 'tempdb'

OPEN db_cursor 
       FETCH NEXT FROM db_cursor INTO @Log_name, @Db_name, @Recovery_model_desc
       WHILE @@FETCH_STATUS =
       BEGIN 
              SET @SQL = N'
              ALTER DATABASE '+ @Db_name + N' SET RECOVERY SIMPLE WITH NO_WAIT
              SELECT F.SIZE
              FROM MASTER.SYS.MASTER_FILES F INNER JOIN MASTER.SYS.DATABASES DB
              ON DB.DATABASE_ID = F.DATABASE_ID
              WHERE F.NAME = ''' + @Log_name +''' AND DB.NAME =  ''' + @Db_name+'''
              '

              SET @SQL = @sql +'
              USE [' + @Db_name + ']
              DBCC SHRINKFILE (' + @Log_name + ', 10)';
             
              SET @sql = @sql + N'
              SELECT F.SIZE
              FROM MASTER.SYS.MASTER_FILES F INNER JOIN MASTER.SYS.DATABASES DB
              ON DB.DATABASE_ID = F.DATABASE_ID
              WHERE F.NAME = ''' + @Log_name +''' AND DB.NAME =  '''+ @Db_name+'''
              '
             
              SET @SQL = @SQL + N'
              ALTER DATABASE ' + @Db_name + N' SET RECOVERY ' + @Recovery_model_desc + ' WITH NO_WAIT
              '

              SET @ParmDefinition =N'@Size int OUTPUT';
              EXECUTE sp_executesql @SQL ,@ParmDefinition,@Size = @SizeAfter OUTPUT;
              FETCH NEXT FROM db_cursor INTO @Log_name, @Db_name, @Recovery_model_desc
       END 

CLOSE db_cursor
DEALLOCATE db_cursor

If you find this solution useful, you are welcome to press one of the ads in this page.. Thanks!

22 comments:

  1. Thank you for putting it together.

    ReplyDelete
  2. Hi Gilad,

    Thank you for the script :)

    It would be better if you can change the DBCC shrink to

    DBCC SHRINKFILE (''' + @Log_name + ''', 10)';

    to prevent any syntax issue.

    ReplyDelete
  3. declare @db varchar(255)
    declare c cursor for
    select name from sys.databases where is_read_only=0 and state=0
    and name not in ('master','model','tempdb','msdb')
    open c
    fetch c into @db
    while @@fetch_status=0
    begin
    EXEC('use '+@db+';ALTER DATABASE '+@db+' SET RECOVERY SIMPLE;DBCC SHRINKFILE ('+@db+'_Log, 1);ALTER DATABASE '+@db+' SET RECOVERY FULL; ');
    fetch next from c into @db
    end
    close c
    deallocate c

    ReplyDelete
  4. Why do you have to change the recovery mode to to simple? What if I want to shrink the trans logs without wiping out the trans history? Say I just ran a log backup job and want to shrink the logs of 60 databases on a SharePoint server? I def do not want to put them into simple mode.

    ReplyDelete