Skrypt generujący polecenia backup dla całego serwera SQL

Wrzucam skrypcik popełniony już jakiś czas temu. Potrzeba wykonania szybko backupu, wraz z jego zrównolegleniem do kilku plików i unikalną nazwą zaowocowały poniższym kodem.

ZAŁOŻENIA:

  • generowanie dla ścieżek sieciowych (lub lokalnych dyskowych) poprzez parametr,
  • wygenerować polecenia backup wszystkich baz na serwerze tak by można było je przekopiować i uruchomić (skrypt sam nie uruchamia backupów),
  • przyspieszenie wykonywania backupów poprzez zrównoleglenie ich wykonywania do kilku plików na raz (o nazwie *_partX gdzie X to numer pliku) – ilość plików ma być konfigurowalna (jak pokazują testy, backup przez sieć 1Gbit do 6 plików przyspiesza ich robienie ponad dwukrotnie),
  • w nazwie plików maja znaleźć się nazwa serwera (i instancji) oraz data wykonania przy czym włączenie ma być parametryzowane,
  • skrypt ma również wygenerować backup baz systemowych (bez zrównoleglania) – włączenie przez parametr,
  • opcjonalnie konfiguracja polecenia STATS czyli co ile procent SQL ma zwracać status wykonania backupu,
  • baza musi być w trybie ONLINE by skrypt ja wziął pod uwagę.

SKRYPT:

DECLARE @CZY_BACKUPOWAC_SYSTEMOWE_BAZY BIT = 1;
 --czy zrobic backup baz master/model/msdb?

DECLARE @ZROWNOLEGLENIE_PLIKOW_BAK TINYINT = 6; 
--czyli na ile plikow zrownoleglic backup? 6 optymalne w testach empirycznych dla sieci 1Gbit
--bazy systemowe zrzucane sa jednak zawsze dla jednego pliku

DECLARE @SCIEZKA_BACKUPU VARCHAR(MAX) = 'C:\BACKUP\';
--pelna sciezka do udzialu sieciowego w ktorej znajdzie sie backup. Koniecznie z pojedynczym \ na koncu!
--TODO: napisac o koniecznoscui uprawnien

DECLARE @CZY_NAZWAC_BACKUP_OD_INSTANCJI BIT =1;
--czy w nazwie backupu ma byc zawarta rowniez nazwa serwera i instancji

DECLARE @CZY_DODAC_DO_NAZWY_AKTUALNA_DATE_I_CZAS BIT = 1;
--czy w nazwie ma rowniez znajdowac sie data uruchomienia backupu

DECLARE @PARAMETR_STATS_PODCZAS_BACKUPU VARCHAR(3) = '20';
--czyli co ile % ma pokazywać się status z wykonywania backupu


/* 
		  MAIN CODE 
						  */

DECLARE @SQL VARCHAR(MAX);
DECLARE @RESULTS TABLE
    (
      id INT IDENTITY
             PRIMARY KEY ,
      SQLBACKUP VARCHAR(MAX)
    );
DECLARE @NOW DATETIME; 
DECLARE @NOW_STRING_FILENAME VARCHAR(MAX); 

DECLARE @SERVERNAME VARCHAR(MAX) = REPLACE(@@SERVERNAME, '\', '_') + '_';


IF @CZY_BACKUPOWAC_SYSTEMOWE_BAZY = 1
    BEGIN
	   --master
        SET @NOW = GETDATE();
        SET @NOW_STRING_FILENAME = '_'
            + REPLACE(REPLACE(CONVERT(VARCHAR(MAX), @NOW, 20), ' ', '_'), ':',
                      '');
        
        SET @SQL = 'BACKUP DATABASE [master] TO  DISK = N'''
            + @SCIEZKA_BACKUPU
            + CASE WHEN @CZY_NAZWAC_BACKUP_OD_INSTANCJI = 1 THEN @SERVERNAME
                   ELSE ''
              END + 'master'
            + CASE WHEN @CZY_DODAC_DO_NAZWY_AKTUALNA_DATE_I_CZAS = 1
                   THEN @NOW_STRING_FILENAME
                   ELSE ''
              END
            + '.bak'' WITH NOFORMAT, NOINIT,  NAME = N''master-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = '
            + @PARAMETR_STATS_PODCZAS_BACKUPU;

        INSERT  INTO @RESULTS
                ( SQLBACKUP )
        VALUES  ( @SQL );

		  --RESET @SQL
        SET @SQL = NULL;

	   --model
        SET @NOW = GETDATE();
        SET @NOW_STRING_FILENAME = '_'
            + REPLACE(REPLACE(CONVERT(VARCHAR(MAX), @NOW, 20), ' ', '_'), ':',
                      '');
        SET @SQL = 'BACKUP DATABASE [model] TO  DISK = N''' + @SCIEZKA_BACKUPU
            + CASE WHEN @CZY_NAZWAC_BACKUP_OD_INSTANCJI = 1 THEN @SERVERNAME
                   ELSE ''
              END + 'model'
            + CASE WHEN @CZY_DODAC_DO_NAZWY_AKTUALNA_DATE_I_CZAS = 1
                   THEN @NOW_STRING_FILENAME
                   ELSE ''
              END
            + '.bak'' WITH NOFORMAT, NOINIT,  NAME = N''model-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = '
            + @PARAMETR_STATS_PODCZAS_BACKUPU;

        INSERT  INTO @RESULTS
                ( SQLBACKUP )
        VALUES  ( @SQL );

	   --msdb
        SET @SQL = 'BACKUP DATABASE [msdb] TO  DISK = N''' + @SCIEZKA_BACKUPU
            + CASE WHEN @CZY_NAZWAC_BACKUP_OD_INSTANCJI = 1 THEN @SERVERNAME
                   ELSE ''
              END + 'msdb'
            + CASE WHEN @CZY_DODAC_DO_NAZWY_AKTUALNA_DATE_I_CZAS = 1
                   THEN @NOW_STRING_FILENAME
                   ELSE ''
              END
            + '.bak'' WITH NOFORMAT, NOINIT,  NAME = N''msdb-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = '
            + @PARAMETR_STATS_PODCZAS_BACKUPU;

        INSERT  INTO @RESULTS
                ( SQLBACKUP )
        VALUES  ( @SQL );

       
    END;
--IF @CZY_BACKUPOWAC_SYSTEMOWE_BAZY = 1


DECLARE @DATABASES_TO_BACKUP TABLE
    (
      dbname sysname PRIMARY KEY
    );
DECLARE @currdb sysname;
DECLARE @FriendlyDatabaseFilename VARCHAR(MAX);

DECLARE @i INT;

INSERT  INTO @DATABASES_TO_BACKUP
        ( dbname
        )
        SELECT  name
        FROM    sys.databases
        WHERE   name NOT IN ( 'master', 'model', 'msdb', 'tempdb' )
                AND source_database_id IS NULL
                AND state_desc = 'ONLINE';




WHILE EXISTS ( SELECT TOP 1
                        1
               FROM     @DATABASES_TO_BACKUP )
    BEGIN

        SELECT TOP 1
                @currdb = dbname
        FROM    @DATABASES_TO_BACKUP
        ORDER BY dbname;

	   --trzeba podmienic wystapienia wszelkich zastrzezonych znakow w nazwie bazy jesli zamierzamy jej uzyc w nazwie pliku
        SET @FriendlyDatabaseFilename = @currdb;
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '<',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '>',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, ':',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '"',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '/',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '\',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '|',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '?',
                                                '_');
        SET @FriendlyDatabaseFilename = REPLACE(@FriendlyDatabaseFilename, '*',
                                                '_');
        SET @NOW = GETDATE();
        SET @NOW_STRING_FILENAME = '_'
            + REPLACE(REPLACE(CONVERT(VARCHAR(MAX), @NOW, 20), ' ', '_'), ':',
                      '');
        SET @SQL = 'BACKUP DATABASE [' + @currdb + '] TO  ';
	   
        IF @ZROWNOLEGLENIE_PLIKOW_BAK > 1 --zapisujemy do kilku plikow
            BEGIN
                SET @i = 0;
                WHILE ( @i < @ZROWNOLEGLENIE_PLIKOW_BAK )
                    BEGIN
                        SET @SQL += CHAR(13) + CHAR(10)
                            + CASE WHEN @i = 0 THEN ''
                                   ELSE ','
                              END;--nowy wiersz i przecinek jesli to nie pierwszy plik
                        SET @SQL += 'DISK = N''' + @SCIEZKA_BACKUPU
                            + CASE WHEN @CZY_NAZWAC_BACKUP_OD_INSTANCJI = 1
                                   THEN @SERVERNAME
                                   ELSE ''
                              END + @FriendlyDatabaseFilename
                            + CASE WHEN @CZY_DODAC_DO_NAZWY_AKTUALNA_DATE_I_CZAS = 1
                                   THEN @NOW_STRING_FILENAME
                                   ELSE ''
                              END + '_part' + CAST(@i + 1 AS VARCHAR(MAX))
                            + '.bak''';

                        SET @i += 1;
                    END;
                SET @SQL += CHAR(13) + CHAR(10)
                    + ' WITH NOFORMAT, NOINIT,  NAME = N''' + @currdb
                    + '-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = '
                    + @PARAMETR_STATS_PODCZAS_BACKUPU;
            END;

        ELSE
            BEGIN

                SET @SQL += 'DISK = N''' + @SCIEZKA_BACKUPU
                    + CASE WHEN @CZY_NAZWAC_BACKUP_OD_INSTANCJI = 1
                           THEN @SERVERNAME
                           ELSE ''
                      END + @FriendlyDatabaseFilename
                    + CASE WHEN @CZY_DODAC_DO_NAZWY_AKTUALNA_DATE_I_CZAS = 1
                           THEN @NOW_STRING_FILENAME
                           ELSE ''
                      END
                    + '.bak'' WITH NOFORMAT, NOINIT,  NAME = N''model-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = '
                    + @PARAMETR_STATS_PODCZAS_BACKUPU;
            END;

        INSERT  INTO @RESULTS
                ( SQLBACKUP )
        VALUES  ( @SQL );
    
        DELETE  FROM @DATABASES_TO_BACKUP
        WHERE   dbname = @currdb;
        SET @SQL = NULL;
        SET @FriendlyDatabaseFilename = NULL;
        SET @currdb = NULL;

    END;


SELECT  *
FROM    @RESULTS;

 

PRZYKŁADOWY OUTPUT:

Dla parametrów identycznych jak w skrypcie powyżej i bazy AdventureWorks2012

BACKUP DATABASE [AdventureWorks2012] TO    DISK = N'C:\BACKUP\WINSQL_SQL2016ENT_AdventureWorks2012_2017-03-27_200836_part1.bak'  ,DISK = N'C:\BACKUP\WINSQL_SQL2016ENT_AdventureWorks2012_2017-03-27_200836_part2.bak'  ,DISK = N'C:\BACKUP\WINSQL_SQL2016ENT_AdventureWorks2012_2017-03-27_200836_part3.bak'  ,DISK = N'C:\BACKUP\WINSQL_SQL2016ENT_AdventureWorks2012_2017-03-27_200836_part4.bak'  ,DISK = N'C:\BACKUP\WINSQL_SQL2016ENT_AdventureWorks2012_2017-03-27_200836_part5.bak'  ,DISK = N'C:\BACKUP\WINSQL_SQL2016ENT_AdventureWorks2012_2017-03-27_200836_part6.bak'   WITH NOFORMAT, NOINIT,  NAME = N'AdventureWorks2012-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = 20
SKRYPT PIERWOTNIE OPUBLIKOWANY JAKO TSQL na dziś #41

Dodaj komentarz