Zweck

ShrinkAllLogs verkleinert die Transaktionslog‑Dateien aller (oder gefilterten) benutzerdefinierten Datenbanken auf eine bestimmte Zielgröße, die einen konfigurierbaren Prozentsatz an freiem Platz belässt. Optional kann vor dem Shrink ein Log‑Backup durchgeführt werden, um Platz freizugeben (nur im vollständigen Recovery‑Modell nötig).

Parameter

 
 
Parameter Typ Default Beschreibung
@dbname SYSNAME '%' Filter für Datenbanknamen (LIKE). % bedeutet alle.
@TargetPercentFree TINYINT 10 Wie viel Prozent der aktuellen Log‑Größe nach dem Shrink als freier Platz erhalten bleiben sollen (0‑100). 0 = maximales Shrink.
@BackupLogBeforeShrink BIT 1 Bei 1 und Recovery‑Modell = FULL wird ein Log‑Backup auf NUL (Dummy) ausgeführt, um inaktiven Platz freizugeben. Für Produktion anpassen!

Ausgabe

Die Prozedur gibt eine Ergebnistabelle zurück:

 
 
Spalte Bedeutung
dbname Name der Datenbank
LogSize_MB_Before Log‑Größe vor dem Shrink (MB)
LogSize_MB_After Log‑Größe nach dem Shrink (MB)
Shrinked_MB Differenz (vorher – nachher)

 

Beispiele

-- Alle Datenbanken, 20% freien Platz lassen, Log-Backup nur bei FULL
EXEC dbo.ShrinkAllLogs @TargetPercentFree = 20, @BackupLogBeforeShrink = 1;

-- Nur Datenbank 'SalesDB', maximales Shrink (0% frei), kein Log-Backup
EXEC dbo.ShrinkAllLogs @dbname = 'SalesDB', @TargetPercentFree = 0, @BackupLogBeforeShrink = 0;

 

USE master;
GO

CREATE OR ALTER PROCEDURE dbo.ShrinkAllLogs
    @dbname SYSNAME = '%',                -- Filter für Datenbanknamen (LIKE)
    @TargetPercentFree TINYINT = 10,      -- Wieviel % freier Platz soll nach Shrink bleiben (0-100)
    @BackupLogBeforeShrink BIT = 1        -- Bei vollständigem Recovery-Modell Log sichern?
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @sqlcmd NVARCHAR(MAX) = N'';
    DECLARE @cr CHAR(1) = CHAR(13);
    DECLARE @lf CHAR(1) = CHAR(10);

    -- Tabelle für Start- und Endgrößen
    DECLARE @workvar TABLE (
        dbname SYSNAME,
        dbid INT,
        SizeStartInMB NUMERIC(15,2),
        SizeEndInMB NUMERIC(15,2),
        Differenz AS (SizeStartInMB - SizeEndInMB)
    );

    -- 1. Startgrößen erfassen (aus sys.master_files)
    INSERT INTO @workvar (dbname, dbid, SizeStartInMB)
    SELECT
        d.name,
        d.database_id,
        CAST(SUM(f.size * 8.0 / 1024) AS NUMERIC(15,2)) AS LogSizeMB
    FROM sys.databases d
    INNER JOIN sys.master_files f ON d.database_id = f.database_id
    WHERE d.database_id > 4
      AND d.state = 0                     -- nur ONLINE
      AND d.name LIKE @dbname
      AND f.type = 1                      -- Log-Dateien
    GROUP BY d.name, d.database_id;

    -- Falls keine Datenbank gefunden wurde
    IF NOT EXISTS (SELECT 1 FROM @workvar)
    BEGIN
        PRINT 'Keine passende Online-Datenbank gefunden.';
        RETURN;
    END;

    -- 2. Dynamisches SQL zum Shrink erzeugen (sicher mit QUOTENAME)
    SELECT @sqlcmd = @sqlcmd +
        N'USE ' + QUOTENAME(d.name) + N'; ' +
        CASE WHEN @BackupLogBeforeShrink = 1 AND d.recovery_model_desc = 'FULL'
             THEN N'BACKUP LOG ' + QUOTENAME(d.name) + N' TO DISK = ''NUL''; '   -- Dummy-Backup (nur für Freigabe)
             ELSE N''
        END +
        N'CHECKPOINT; ' +
        N'DBCC SHRINKFILE (' + QUOTENAME(f.name) + N', ' + 
            CAST((CAST(f.size AS BIGINT) * 8 / 1024 * (100 - @TargetPercentFree) / 100) AS VARCHAR(20)) + N') WITH NO_INFOMSGS;' +
        @cr + @lf
    FROM sys.databases d
    INNER JOIN sys.master_files f ON d.database_id = f.database_id
    WHERE d.database_id > 4
      AND d.state = 0
      AND d.name LIKE @dbname
      AND f.type = 1;

    -- 3. Ausführung (mit Fehlerbehandlung)
    BEGIN TRY
        EXEC sp_executesql @sqlcmd;
    END TRY
    BEGIN CATCH
        PRINT 'Fehler beim Shrink: ' + ERROR_MESSAGE();
        -- Hier könnte man auch RAISERROR verwenden
    END CATCH

    -- 4. Endgrößen erfassen
    UPDATE w
    SET w.SizeEndInMB = CAST((
        SELECT SUM(f2.size * 8.0 / 1024)
        FROM sys.master_files f2
        WHERE f2.database_id = w.dbid AND f2.type = 1
    ) AS NUMERIC(15,2))
    FROM @workvar w;

    -- 5. Ergebnis ausgeben
    SELECT
        dbname,
        SizeStartInMB AS [LogSize_MB_Before],
        SizeEndInMB AS [LogSize_MB_After],
        Differenz AS [Shrinked_MB]
    FROM @workvar
    ORDER BY dbname;

    SET NOCOUNT ON;  -- bleibt an
END;
GO