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