Wprowadzenie
Możesz znaleźć wiele poradników na temat tworzenia kopii zapasowych i przywracania baz danych. W tym artykule pokażemy, jak można to zrobić przy użyciu domyślnych środków MS SQL Server.
Ten przykład obejmie kilka podejść – od sprawdzenia integralności bazy danych przed utworzeniem jej kopii zapasowej po przywrócenie bazy danych z wcześniej utworzonej kopii zapasowej.
Rozwiązanie
Najpierw spójrzmy na ogólny algorytm, którego użyjemy do tworzenia kopii zapasowej bazy danych:
1) Zdefiniowanie, które bazy danych wymagają archiwizacji
2) Sprawdzenie integralności wybranych baz danych
3) Utworzenie kopii zapasowej (pełnej, różnicowej lub kopii dziennika transakcji) dla każdej z wybranych baz danych
4) Sprawdzanie utworzonych kopii zapasowych
5) Kompresowanie dzienników transakcji (w razie potrzeby)
Poniżej znajduje się przykład implementacji tego algorytmu.
Aby określić, które bazy danych wymagają kopii zapasowej, utworzymy następującą tabelę:
UŻYJ [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[BackupSettings]( [DBID] [int] NOT NULL, [FullPathBackup] [nvarchar](255) NOT NULL, [DiffPathBackup] [nvarchar](255 ) NULL, [LogPathBackup] [nvarchar](255) NULL, [InsertUTCDate] [data i godzina] NIE NULL, OGRANICZENIE [PK_BackupSettings] KLUCZ PODSTAWOWY ([DBID] ASC) Z (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_D, IGNORE_D ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY];TABELA GOALTERÓW [srv].[BackupSettings] DODAJ OGRANICZENIE [DF_BackupSettings_InsertUTCDate] DOMYŚLNE (getutcdate()) DLA [InsertUTCDate];GO
Identyfikator bazy danych znajduje się w pierwszej kolumnie, „FullPathBackup” zawiera ścieżkę do tworzenia pełnej kopii zapasowej (na przykład „disk:\…\”), a DiffPathBackup i LogPathBackup zawierają pełne ścieżki do tworzenia kopii różnicowych i dzienników transakcji odpowiednio. Jeśli kolumny DiffPathBackup lub LogPathBackup są puste, kopia dziennika różnicowego i/lub transakcyjnego dla tej bazy danych nie zostanie utworzona.
Możemy również stworzyć reprezentację na podstawie tej tabeli:
UŻYJ [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE widok [srv].[vBackupSettings]asSELECT [DBID] ,DB_Name([DBID]) jako [DBName] ,[FullPathBackup] ,[DiffPathBackup] ,[UTT. ] Z [srv].[Ustawienia kopii zapasowej];GO
Ta reprezentacja pozwala skutecznie sprawdzić, które bazy danych biorą udział w procesie tworzenia kopii zapasowej.
Teraz utwórzmy reprezentację, która wyświetla informacje o pliku bazy danych z reprezentacji systemu sys.master_files:
USE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE widok [inf].[ServerDBFileInfo] asSELECT @@Servername AS Server , File_id ,--DB identyfikator pliku. Wartość bazowa identyfikatora pliku to 1 Type_desc ,--Wpisz opis pliku Nazwa jako [Nazwa_pliku] ,--DB nazwa pliku logicznego LEFT(Nazwa_fizyczna, 1) AS Napęd ,--Flaga lokalizacji pliku DB Nazwa_fizyczna ,--Pełny plik nazwa w systemie operacyjnym PRAWO(nazwa_fizyczna, 3) AS Ext ,--Rozszerzenie pliku Rozmiar jako CountPage, --Aktualny rozmiar pliku w stronach 8Kb round((cast(Size*8 as float))/1024,3) jako SizeMb, - -Rozmiar pliku w Mb round((cast(Size*8 as float))/1024/1024,3) jako SizeGb, --Rozmiar pliku w przypadku Gb, gdy is_percent_growth=0, a następnie Wzrost*8 w przeciwnym razie 0 kończy się jako Wzrost, -- Wzrost pliku na stronach 8Kb, gdy is_percent_growth=0 then round((cast(Growth*8 as float))/1024,3) end as GrowthMb, --Rozrost pliku w przypadku Mb, gdy is_percent_growth=0 then round((cast(Wzrost *8 as float))/1024/1024,3) kończy się jako GrowthGb, --Przyrost pliku w przypadku GB, gdy is_percent_growth=1, a następnie Wzrost w przeciwnym razie 0 kończy się jako GrowthPercent, --File growth in percent is_percent_growth, --Percent growth atrybut database_id , DB_ Name(database_id) jako [DB_Name], State,--Stan pliku state_desc jako StateDesc,--Opis stanu pliku is_media_read_only jako IsMediaReadOnly,--Plik znajduje się na dysku jako tylko do odczytu (0 - i do zapisu) is_read_only jako IsReadOnly ,--file jest oznaczony jako tylko do odczytu (0 - i do zapisu) is_sparse jako IsSpace,--Sparse plik is_name_reserved jako IsNameReserved,--1 - Zdalna nazwa pliku, dostępna do użycia. --Konieczne jest wykonanie kopii zapasowej logu przed ponownym użyciem tej samej nazwy (nazwa lub argumenty nazwa_fizyczna) dla nowego pliku ---0 - Nazwa pliku, niedostępna do użycia create_lsn jako CreateLsn,--Numer rejestracji transakcji w logu (LSN) który został użyty do utworzenia pliku drop_lsn jako DropLsn,--LSN, który został użyty do usunięcia pliku read_only_lsn jako ReadOnlyLsn,--LSN, który był używany przez grupę plików zawierającą plik do zmiany typu „odczyt i zapis” na „odczyt -only" (najnowsza zmiana) read_write_lsn jako ReadWriteLsn,--LSN, który był używany przez grupę plików zawierającą plik do zmiany typu "tylko do odczytu" na "odczyt i zapis" (najnowsza zmiana) différence_base_lsn jako DifferentialBaseLsn,- -Podstawa do różnicowych kopii zapasowych. Zakresy danych, które zostały zmienione po włączeniu LSN do różnicowej kopii zapasowej. différence_base_guid jako DifferentialBaseGuid,--Unikalny identyfikator podstawowej kopii zapasowej, która zostanie użyta do utworzenia kopii różnicowej. différence_base_time jako DifferentialBaseTime,--Czas odpowiadający różnicy_base_lsn redo_start_lsn jako RedoStartLsn,--LSN używany do określenia początku następnego ponawiania --Ma wartość NULL, z wyjątkiem przypadków, w których stan =PRZYWRACANIE lub stan =ODZYSKIWANIE_PENDING redo_start_fork_guid jako RedoStart-ForkG -Unikalny identyfikator punktu rozwidlenia przywracania --first_fork_guid wartość argumentu następnej przywróconej kopii zapasowej powinna być równa tej wartości redo_target_lsn jako RedoTargetLsn,--LSN, który służy jako punkt zatrzymania dla ponownego wykonania trybu "online" w tym pliku -- Ma wartość NULL, z wyjątkiem przypadków, w których stan =PRZYWRACANIE lub stan =RECOVERY_PENDING redo_target_fork_guid jako RedoTargetForkGuid,--Rozwidlenie przywracania, na którym można przywrócić kontener. Używane razem z redo_target_lsn backup_lsn jako BackupLsn--LSN najnowszych danych lub różnicowa kopia zapasowa plikuFROM sys.master_files--database_files;GO
Aby utworzyć pełne kopie zapasowe, zaimplementujmy następującą procedurę składowaną:
[rozwiń tytuł =”Kod „]
USE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER PROCEDURA ONGOALTER [srv].[RunFullBackupDB] @ClearLog bit=1 --określa, czy rozmiar dziennika transakcji powinien zostać zmniejszonyASBEGIN /* Tworzenie pełnej kopii zapasowej bazy danych i sprawdzanie jej integralności wcześniej */ USTAWIĆ NR NA; zadeklaruj @dt datetime=getdate(); zadeklaruj @rok int=ROK(@dt); zadeklaruj @miesiąc int=MIESIĄC(@dt); zadeklaruj @day int=DZIEŃ(@dt); zadeklaruj @hour int=DatePart(godzina, @dt); zadeklaruj @minute int=DataCzęść(minuta, @dt); zadeklaruj @second int=DatePart(druga, @dt); zadeklaruj @pathBackup nvarchar(255); zadeklaruj @pathstr nvarchar(255); zadeklaruj @DBName nvarchar(255); zadeklaruj @backupName nvarchar(255); zadeklaruj @ sql nvarchar(max); zadeklaruj @backupSetId jako int; zadeklaruj @FileNameLog nvarchar(255); define @tbllog table( [DBName] [nvarchar](255) NOT NULL, [FileNameLog] [nvarchar](255) NOT NULL ); zadeklaruj @tbl table ( [DBName] [nvarchar](255) NOT NULL, [FullPathBackup] [nvarchar](255) NOT NULL ); --Pobieranie nazwy bazy danych i pełnych ścieżek do tworzenia pełnej kopii zapasowej wstaw do @tbl ( [NazwaDB] ,[FullPathBackup] ) wybierz DB_NAME([DBID]) ,[FullPathBackup] z [srv].[BackupSettings]; --Pobieranie nazwy bazy danych i nazw odpowiednich dzienników transakcji (ponieważ jedna baza danych może mieć wiele dzienników) wstaw do @tbllog([nazwa_bazy_danych], [rejestr_nazw_pliku]) wybierz t.[nazwa_pliku], tt.[nazwa_pliku] jako [log_nazwa_pliku] ] z @tbl as t sprzężenie wewnętrzne [inf].[ServerDBFileInfo] as tt on t.[DBName]=DB_NAME(tt.[database_id]) gdzie tt.[Type_desc]='LOG'; --sekwencyjne przetwarzanie każdego z baz danych, które otrzymaliśmy wcześniej while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; wybierz top(1) @DBName=[DBName], @pathBackup=[FullPathBackup] z @tbl; set @[email protected]+N'_Full_backup_'+cast(@rok jako nvarchar(255))+N'_'+cast(@miesiąc jako nvarchar(255))+N'_'+cast(@dzień jako nvarchar(255))--+N'_' --+cast(@godzina jako nvarchar(255))+N'_'+cast(@minuta jako nvarchar(255))+N'_'+cast(@ drugi jako nvarchar(255)); ustaw @[email protected]@sqldat.com+N'.bak'; --sprawdzanie bazy danych pod kątem integralności @sql=N'DBCC CHECKDB(N'+N''''[email protected]+N''''+N') WITH NO_INFOMSGS'; exec(@sql); --wykonywanie procedury tworzenia kopii zapasowej set @sql=N'BACKUP DATABASE ['[email protected]+N'] TO DISK =N'+N''''[email protected]+N''''+ N' WITH NOFORMAT, NOINIT, NAME =N'+N''''[email protected]+N''''+ N', SUMA KONTROLNA, STOP_ON_ERROR, SKIP, REWIND, KOMPRESJA, STATS =10;'; exec(@sql); --sprawdzenie utworzonej kopii zapasowej wybierz @backupSetId =pozycja z msdb..backupset gdzie [email protected] i backup_set_id=(wybierz max(backup_set_id) z msdb..backupset gdzie [email protected]); set @sql=N'Błąd weryfikacji. Nie znaleziono informacji o kopii zapasowej bazy danych „'[email protected]+'”.'; jeśli @backupSetId ma wartość null begin raiserror(@sql, 16, 1) end else begin set @sql=N'PRZYWRÓĆ TYLKO Z DYSKU =N'+''''[email protected]+N''''+N' Z PLIKEM ='+cast(@backupSetId jako nvarchar(255)); exec(@sql); end --kompresja dzienników transakcji bazy danych if(@ClearLog=1) begin while(exists(select top(1) 1 z @tbllog gdzie [DBName][email protected])) begin select top(1) @FileNameLog=FileNameLog z @tbllog gdzie [email protected]; set @sql=N'USE ['[email protected]+N'];'+N' DBCC SHRINKFILE (N'+N''''[email protected]+N''''+N' , 0 , TYLKO OBCIĄGNIĘTY)”; exec(@sql); usuń z @tbllog, gdzie [email protected] i [email protected]; koniec koniec usuń z @tbl gdzie [nazwa_bazy_danych][email protected]; koniecENDGO
[/rozwiń]
Zgodnie z kodem widzimy, że ta procedura zapewnia rozwiązanie dla pozostałych kroków algorytmu tworzenia kopii zapasowej.
W podobny sposób implementuje się procedury tworzące kopie różnicowe i dziennika transakcji:
[rozwiń tytuł =”Kod „]
USE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER PROCEDURA ONGOALTER [srv].[RunDiffBackupDB] @ClearLog bit=1 --określa, czy rozmiar dziennika transakcji powinien zostać zmniejszonyASBEGIN /* Tworzenie różnicowej kopii zapasowej bazy danych */ SET NOCOUNT ON; zadeklaruj @dt datetime=getdate(); zadeklaruj @rok int=ROK(@dt); zadeklaruj @miesiąc int=MIESIĄC(@dt); zadeklaruj @day int=DZIEŃ(@dt); zadeklaruj @hour int=DatePart(godzina, @dt); zadeklaruj @minute int=DataCzęść(minuta, @dt); zadeklaruj @second int=DatePart(druga, @dt); zadeklaruj @pathBackup nvarchar(255); zadeklaruj @pathstr nvarchar(255); zadeklaruj @DBName nvarchar(255); zadeklaruj @backupName nvarchar(255); zadeklaruj @ sql nvarchar(max); zadeklaruj @backupSetId jako int; zadeklaruj @FileNameLog nvarchar(255); zadeklaruj tabelę @tbl ( [DBName] [nvarchar](255) NOT NULL, [DiffPathBackup] [nvarchar](255) NOT NULL ); define @tbllog table( [DBName] [nvarchar](255) NOT NULL, [FileNameLog] [nvarchar](255) NOT NULL ); --Pobieranie nazwy bazy danych i pełnych ścieżek do tworzenia różnicowych kopii zapasowych, wstaw do @tbl ( [NazwaDB] ,[DiffPathBackup] ) wybierz DB_NAME([DBID]) ,[DiffPathBackup] z [srv].[BackupSettings] gdzie [DiffPathBackup] nie jest pusta; --Pobieranie nazwy bazy danych i pełnych nazw odpowiednich plików dziennika transakcji (ponieważ jedna baza danych może mieć wiele dzienników) wstaw do @tbllog([NazwaDB], [DziennikNazwyPliku]) wybierz t.[NazwaBazy], tt.[NazwaPliku] jako [FileNameLog] z @tbl as t sprzężenie wewnętrzne [inf].[ServerDBFileInfo] as tt on t.[DBName]=DB_NAME(tt.[database_id]) gdzie tt.[Type_desc]='LOG'; --sekwencyjne przetwarzanie każdego z baz danych, które otrzymaliśmy wcześniej while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; wybierz top(1) @DBName=[DBName], @pathBackup=[DiffPathBackup] z @tbl; set @[email protected]+N'_Diff_backup_'+cast(@rok jako nvarchar(255))+N'_'+cast(@miesiąc jako nvarchar(255))+N'_'+cast(@dzień jako nvarchar(255))+N'_' +cast(@hour as nvarchar(255))+N'_'+cast(@minute as nvarchar(255))+N'_'+cast(@second as nvarchar( 255)); ustaw @[email protected]@sqldat.com+N'.bak'; --sprawdzanie bazy danych pod kątem integralności @sql=N'DBCC CHECKDB(N'+N''''[email protected]+N''''+N') WITH NO_INFOMSGS'; exec(@sql); --wykonywanie procedury tworzenia kopii zapasowej set @sql=N'BACKUP DATABASE ['[email protected]+N'] TO DISK =N'+N''''[email protected]+N''''+ N' Z RÓŻNICĄ, NOFORMAT, NOINIT, NAZWA =N'+N''''[email protected]+N''''+N', SUMA KONTROLNA, STOP_ON_ERROR, SKIP, REWIND, COMPRESSION, STATS =10;'; exec(@sql); --sprawdzenie kopii zapasowej, którą właśnie utworzyliśmy select @backupSetId =pozycja z msdb..backupset gdzie [email protected] i backup_set_id=(wybierz max(backup_set_id) z msdb..backupset gdzie [email protected]); set @sql=N'Błąd weryfikacji. Nie znaleziono informacji o kopii zapasowej bazy danych „'[email protected]+'”.'; jeśli @backupSetId ma wartość null begin raiserror(@sql, 16, 1) end else begin set @sql=N'PRZYWRÓĆ TYLKO Z DYSKU =N'+''''[email protected]+N''''+N' Z PLIKEM ='+cast(@backupSetId jako nvarchar(255)); exec(@sql); end --kompresja dzienników transakcji bazy danych if(@ClearLog=1) begin while(exists(select top(1) 1 z @tbllog gdzie [DBName][email protected])) begin select top(1) @FileNameLog=FileNameLog z @tbllog gdzie [email protected]; set @sql=N'USE ['[email protected]+N'];'+N' DBCC SHRINKFILE (N'+N''''[email protected]+N''''+N' , 0 , TYLKO OBCIĄGNIĘTY)”; exec(@sql); usuń z @tbllog, gdzie [email protected] i [email protected]; koniec koniec usuń z @tbl gdzie [nazwa_bazy_danych][email protected]; koniecENDGO
[/rozwiń]
Ponieważ sprawdzanie baz danych pod kątem integralności zajmuje dużo zasobów, możemy je pominąć podczas tworzenia różnicowej kopii zapasowej.
[rozwiń tytuł =”Kod „]
USE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER PROCEDURA ONGOALTER [srv].[RunLogBackupDB] @ClearLog bit=1 --określa, czy rozmiar dziennika transakcji powinien zostać zmniejszonyASBEGIN /* Tworzenie kopii zapasowej dziennika transakcji bazy danych */ SET NOCOUNT ON; zadeklaruj @dt datetime=getdate(); zadeklaruj @rok int=ROK(@dt); zadeklaruj @miesiąc int=MIESIĄC(@dt); zadeklaruj @day int=DZIEŃ(@dt); zadeklaruj @hour int=DatePart(godzina, @dt); zadeklaruj @minute int=DataCzęść(minuta, @dt); zadeklaruj @second int=DatePart(druga, @dt); zadeklaruj @pathBackup nvarchar(255); zadeklaruj @pathstr nvarchar(255); zadeklaruj @DBName nvarchar(255); zadeklaruj @backupName nvarchar(255); zadeklaruj @ sql nvarchar(max); zadeklaruj @backupSetId jako int; zadeklaruj @FileNameLog nvarchar(255); zadeklaruj tabelę @tbl ( [DBName] [nvarchar](255) NOT NULL, [LogPathBackup] [nvarchar](255) NOT NULL ); define @tbllog table( [DBName] [nvarchar](255) NOT NULL, [FileNameLog] [nvarchar](255) NOT NULL ); — Pobieranie nazw baz danych i pełnych ścieżek w celu tworzenia kopii zapasowych dzienników transakcji za pomocą nieprostego modelu odzyskiwania (pełne lub zbiorcze rejestrowane). Systemowe bazy danych są również wykluczone wstaw do @tbl ( [DBName] ,[LogPathBackup] ) wybierz DB_NAME(b.[DBID]) ,b.[LogPathBackup] z [srv].[BackupSettings] jako b wewnętrzne łączenie sys.databases jako d on b.[DBID]=d.[database_id] gdzie d.recovery_model<3 i DB_NAME([DBID]) nie w ( N'master', N'tempdb', N'model', N'msdb', N' ReportServer', N'ReportServerTempDB' ) i [LogPathBackup] nie ma wartości NULL; --Pobieranie nazwy bazy danych i pełnych nazw odpowiednich plików dziennika transakcji (ponieważ jedna baza danych może mieć wiele dzienników) wstaw do @tbllog([NazwaDB], [DziennikNazwyPliku]) wybierz t.[NazwaBazy], tt.[NazwaPliku] jako [FileNameLog] z @tbl as t sprzężenie wewnętrzne [inf].[ServerDBFileInfo] as tt on t.[DBName]=DB_NAME(tt.[database_id]) gdzie tt.[Type_desc]='LOG'; --sekwencyjne przetwarzanie każdego z baz danych, które otrzymaliśmy wcześniej while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; wybierz top(1) @DBName=[DBName], @pathBackup=[LogPathBackup] z @tbl; set @[email protected]+N'_Log_backup_'+cast(@rok jako nvarchar(255))+N'_'+cast(@miesiąc jako nvarchar(255))+N'_'+cast(@dzień jako nvarchar(255))+N'_' +cast(@hour as nvarchar(255))+N'_'+cast(@minute as nvarchar(255))+N'_'+cast(@second as nvarchar( 255)); ustaw @[email protected]@sqldat.com+N'.trn'; --wykonywanie procedury tworzenia kopii zapasowej set @sql=N'BACKUP LOG ['[email protected]+N'] TO DISK =N'+N''''[email protected]+N''''+ N' Z NOFORMAT, NOINIT, NAME =N'+N''''[email protected]+N''''+N', SUMA KONTROLNA, STOP_ON_ERROR, SKIP, REWIND, COMPRESSION, STATS =10;'; exec(@sql); --Sprawdzenie kopii zapasowej dziennika transakcji, którą właśnie utworzyliśmy select @backupSetId =pozycja z msdb..backupset gdzie [email protected] i backup_set_id=(wybierz max(backup_set_id) z msdb..backupset gdzie [email protected]); set @sql=N'Błąd weryfikacji. Nie znaleziono informacji o kopii zapasowej bazy danych „'[email protected]+'”.'; jeśli @backupSetId ma wartość null begin raiserror(@sql, 16, 1) end else begin set @sql=N'PRZYWRÓĆ TYLKO Z DYSKU =N'+''''[email protected]+N''''+N' Z PLIKEM ='+cast(@backupSetId jako nvarchar(255)); exec(@sql); end --kompresja dzienników transakcji bazy danych if(@ClearLog=1) begin while(exists(select top(1) 1 z @tbllog gdzie [DBName][email protected])) begin select top(1) @FileNameLog=FileNameLog z @tbllog gdzie [email protected]; set @sql=N'USE ['[email protected]+N'];'+N' DBCC SHRINKFILE (N'+N''''[email protected]+N''''+N' , 0 , TYLKO OBCIĄGNIĘTY)”; exec(@sql); usuń z @tbllog, gdzie [email protected] i [email protected]; koniec koniec usuń z @tbl gdzie [nazwa_bazy_danych][email protected]; koniecENDGO
[/rozwiń]
Jak wspomniano powyżej, sprawdzanie baz danych pod kątem integralności to zadanie wymagające dużej ilości zasobów. W połączeniu z faktem, że kopie zapasowe dziennika transakcji zwykle muszą być tworzone dość często, daje nam to powód, aby pominąć sprawdzanie integralności podczas tworzenia kopii dziennika transakcji.
Należy również pamiętać, że pełne kopie zapasowe baz danych „master”, „msdb” i „model” muszą być wykonywane okresowo.
Aby zautomatyzować proces tworzenia kopii zapasowej, wystarczy umieścić wywołanie wcześniej wdrożonych procedur w Harmonogramie zadań systemu Windows, zadaniach agentów lub dowolnej podobnej dostępnej usłudze.
Będziesz musiał ustawić częstotliwość połączeń dla każdej z tych procedur indywidualnie w oparciu o szczyty obciążenia, plateau aktywności itp.
Podstawowe podejście jest następujące:
1) Tworzenie pełnej kopii zapasowej raz dziennie
2) Tworzenie różnicowych kopii zapasowych co 2-4 godziny
3) Tworzenie kopii zapasowych dziennika transakcji co 5-60 minut
Należy pamiętać, że zazwyczaj bazy danych uczestniczą w bezpiecznym i szybkim systemie dostępu. A jeśli później używa kopii zapasowych dziennika transakcji, niezwykle ważne jest, aby nie zakłócać procedury. Mówiąc dokładniej, oznacza to, że kopie dziennika transakcji nie powinny być tworzone przez kilka różnych procesów – w takim przypadku sekwencja kopii zapasowej z tych kopii zostanie utracona.
Tutaj widzieliśmy przykłady każdej bazy danych przetwarzanej sekwencyjnie, pojedynczo. Równoległe przetwarzanie możemy jednak osiągnąć w środowisku produkcyjnym – pozwalając na wykonanie kilku kopii zapasowych jednocześnie. Można do tego podejść na kilka różnych sposobów. Na przykład, wywołując następującą procedurę składowaną:
UŻYJ [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER PROCEDURA ONGOCREATE [inf].[RunAsyncExecute]( @sql nvarchar(max), @jobname nvarchar(57) =null, @database nvarchar(128)=null, @database nvarchar(128)=null, @database 128) =null)AS BEGIN/* Asynchroniczne wykonanie pakietu za pomocą zadań Agenta RunAsyncExecute - asynchroniczne wykonanie polecenia T-SQL lub zapisanej procedury 2012 Antonin Foller, Motobit Software, www.motobit.com http://www.motobit.com/ tips/detpg_async-execute-sql/ */ SET NOCOUNT ON; zadeklaruj unikalny identyfikator @id; --Utwórz unikalną nazwę zadania, jeśli nazwa nie jest określona, jeśli (@nazwa zadania ma wartość null) set @jobname=''; set @jobname =@jobname + '_async_' + convert(varchar(64),NEWID()); if (@owner is null) set @owner ='sa'; --Utwórz nowe zadanie, pobierz identyfikator zadania wykonaj msdb..sp_add_job @jobname, @[email protected], @[email protected] WYJŚCIE; --Określ serwer zadań dla wykonania zadania msdb..sp_add_jobserver @[email protected]; --Określ pierwszy krok zadania — polecenie SQL --(@on_success_action =3 ... Przejdź do następnego kroku) wykonaj msdb..sp_add_jobstep @[email protected], @step_name='Step1', @command =@sql, @database_name =@database, @on_success_action =3; --Określ następny krok zadania — usuń zadanie zadeklaruj @deletecommand varchar(200); set @deletecommand ='wykonaj msdb..sp_delete_job @job_name='''przykł[email protected]+''''; wykonaj msdb..sp_add_jobstep @[email protected], @step_name='Krok2', @command =@deletecommand; --Uruchom zadanie wykonaj msdb..sp_start_job @[email protected]; ZAKOŃCZ PRACĘ
W tym przypadku asynchronię osiąga się poprzez dynamiczne tworzenie zadań agenta, ich późniejsze wykonywanie i usuwanie.
Przyjrzyjmy się teraz ogólnemu algorytmowi przywracania baz danych z kopii zapasowych utworzonych wcześniej w innym/testowym środowisku:
1) Zdefiniowanie, które bazy danych powinny zostać przywrócone i lokalizacji ich kopii zapasowych
2) Przywrócenie baz danych
3) Sprawdzenie przywróconych baz danych pod kątem integralności
Teraz przyjrzymy się implementacji algorytmu, który przywraca bazę danych z pełnej kopii zapasowej. W przypadku kopii różnicowej procedura jest podobna – jedyną różnicą jest to, że najpierw należy przywrócić pełną kopię zapasową, a następnie kopię różnicową.
Aby określić, które bazy danych mają zostać przywrócone, a także lokalizację ich kopii zapasowych, utwórzmy dwie tabele, jak pokazano poniżej:
UŻYJ [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[RestoreSettings]( [DBName] [nvarchar](255) NOT NULL, [FullPathRestore] [nvarchar](255) NOT NULL, [DiffPathRestore] [n ](255) NIE NULL, [LogPathRestore] [nvarchar](255) NIE NULL, [InsertUTCDate] [datetime] NIE NULL, OGRANICZENIE [PK_RestoreSettings] KLUCZ PODSTAWOWY CLUSTERED ([DBName] ASC) Z (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF , IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY];TABELA GOALTERÓW [srv].[RestoreSettings] DODAJ OGRANICZENIE [DF_RestoreSettings_InsertUTCDate] DEFAULT (getutcdateW tym przypadku przeznaczenie kolumn jest analogiczne do tych z tabeli [srv].[Ustawienia kopii zapasowej]. Jedyna różnica polega na tym, że pełna ścieżka zostanie wykorzystana do zlokalizowania kopii zapasowych do przywrócenia, a nie do tworzenia nowych.
UŻYJ [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[RestoreSettingsDetail]( [Row_GUID] [unikalny identyfikator] NOT NULL, [DBName] [nvarchar](255) NOT NULL, [SourcePathRestore](255char) ) NOT NULL, TargetPathRestore [nvarchar](255) NOT NULL, [Ext] [nvarchar](255) NOT NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_RestoreSettingsDetail] PODSTAWOWY KLUCZ KLASTRA ( [Row_GUID] ASC) PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY];TABELA GOALTERÓW [srv]. DLA [Row_GUID];TABELA GOALTERÓW [srv].[RestoreSettingsDetail] DODAJ OGRANICZENIE [DF_RestoreSettingsDetail_InsertUTCDate] DOMYŚLNE (getutcdate()) DLA [InsertUTCDate];GOTa tabela jest potrzebna do zdefiniowania pełnych nazw plików przywracanej bazy danych, które są następnie używane do dalszego transferu (na przykład [SourcePathRestore]='Nazwa pliku logicznego' i [TargetPathRestore]='dysk:\…\Fizyczna nazwa pliku ', podczas gdy [Ext]='Rozszerzenie pliku')
Właściwie możemy zdefiniować nazwy logiczne plików bazy danych za pomocą następującego zapytania:
PRZYWRACANIE LISTY PLIKÓW TYLKO Z DYSKU ='dysk:\...\kopia zapasowa.BAK';Uzyskanie informacji o kopiach zapasowych znajdujących się w pliku można wykonać w ten sposób:
PRZYWRÓĆ HEADERONLYFROM DISK='dysk:\...\kopia zapasowa.BAK';Następnie mamy implementację procedury składowanej używanej do przywracania bazy danych z pełnej kopii zapasowej i sprawdzania jej pod kątem integralności danych:
[rozwiń tytuł =”Kod „]
USE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER PROCEDURA ONGOALTER [srv].[RunFullRestoreDB]ASBEGIN /* Odzyskiwanie bazy danych z pełnej kopii zapasowej i sprawdzanie integralności bazy danych */ SET NOCOUNT ON; zadeklaruj @dt datetime=DateAdd(dzień,-2,getdate()); zadeklaruj @rok int=ROK(@dt); zadeklaruj @miesiąc int=MIESIĄC(@dt); zadeklaruj @day int=DZIEŃ(@dt); zadeklaruj @hour int=DatePart(godzina, @dt); zadeklaruj @minute int=DataCzęść(minuta, @dt); zadeklaruj @second int=DatePart(druga, @dt); zadeklaruj @pathBackup nvarchar(255); zadeklaruj @pathstr nvarchar(255); zadeklaruj @DBName nvarchar(255); zadeklaruj @backupName nvarchar(255); zadeklaruj @ sql nvarchar(max); zadeklaruj @backupSetId jako int; zadeklaruj @FileNameLog nvarchar(255); zadeklaruj @SourcePathRestore nvarchar(255); zadeklaruj @TargetPathRestore nvarchar(255); zadeklaruj @Ext nvarchar(255); zadeklaruj tabelę @tbl ( [DBName] [nvarchar](255) NOT NULL, [FullPathRestore] [nvarchar](255) NOT NULL ); zadeklaruj @tbl_files table ( [DBName] [nvarchar](255) NOT NULL, [SourcePathRestore] [nvarchar](255) NOT NULL, [TargetPathRestore] [nvarchar](255) NOT NULL, [Ext] [nvarchar](255) NIE JEST ZEREM ); --pobierając listę nazw baz danych i ścieżek do pełnych kopii zapasowych, wstaw do @tbl ( [NazwaDB] ,[PełnaŚcieżka] ) wybierz [NazwaBazyDanej] ,[PełnaŚcieżkaRestore] z [srv].[PrzywróćUstawienia]; --pobieranie szczegółowych informacji o nowej lokalizacji plików DB wstaw do @tbl_files ( [DBName] ,[SourcePathRestore] ,[TargetPathRestore] ,[Ext] ) wybierz [DBName] ,[SourcePathRestore] ,[TargetPathRestore] ,[Ext] z [ srv].[PrzywróćSzczegółyUstawień]; --przetwarzanie każdej bazy danych, którą otrzymaliśmy wcześniej while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; wybierz top(1) @DBName=[DBName], @pathBackup=[FullPathRestore] z @tbl; set @[email protected]+N'_Full_backup_'+cast(@rok jako nvarchar(255))+N'_'+cast(@miesiąc jako nvarchar(255))+N'_'+cast(@dzień jako nvarchar(255))--+N'_' --+cast(@godzina jako nvarchar(255))+N'_'+cast(@minuta jako nvarchar(255))+N'_'+cast(@ drugi jako nvarchar(255)); ustaw @[email protected]@sqldat.com+N'.bak'; --tworzenie zapytania o kopię zapasową i wykonanie jej set @sql=N'RESTORE DATABASE ['[email protected]+N'_Restore] Z DYSKU =N'+N''''[email protected]+N''' '+ N' Z PLIKEM =1,'; while(exists(wybierz top(1) 1 z @tbl_files gdzie [DBName][email protected])) begin wybierz top(1) @SourcePathRestore=[SourcePathRestore], @TargetPathRestore=[TargetPathRestore], @Ext=[Ext] z @tbl_files gdzie [nazwa_bazy_danych][email protected]; ustaw @[email protected]+N' PRZENIEŚ N'+N''''[email protected]+N''''+N' TO N'+N''''[email protected]+N' _Przywróć.'[email protected]+N''''+N','; usuń z @tbl_files, gdzie [DBName][email protected] i [SourcePathRestore][email protected] i [Ext][email protected]; koniec zestawu @[email protected]+N' NOUNLOAD, REPLACE, STATS =5'; exec(@sql); --sprawdzanie bazy danych pod kątem integralności @sql=N'DBCC CHECKDB(N'+N''''[email protected]+'_Restore'+N''''+N') WITH NO_INFOMSGS'; exec(@sql); usuń z @tbl gdzie [nazwa_bazy_danych][email protected]; koniecEND[/rozwiń]
Aby określić, która pełna kopia zapasowa powinna być użyta do przywrócenia, używana jest nazwa pliku o specjalnej strukturze:
_Full_backup_ _ _ .bak Aby zautomatyzować ten proces przywracania bazy danych, wywołanie wdrożonej procedury składowanej powinno zostać umieszczone w Harmonogramie zadań Windows, zadaniach agenta lub dowolnej podobnej dostępnej usłudze.
Możesz zobaczyć najnowsze kopie zapasowe bazy danych, korzystając z następującej reprezentacji:
UŻYJ [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE VIEW [inf].[vServerLastBackupDB] aswith backup_cte as(wybierz bs.[nazwa_bazy], backup_type =case bs.[typ] gdy 'D' następnie 'baza danych' gdy 'L ' następnie 'log' kiedy 'I' następnie 'różnicowe' w przeciwnym razie 'inne' koniec, bs.[first_lsn], bs.[last_lsn], bs.[backup_start_date], bs.[backup_finish_date], cast(bs.[backup_size] jako dziesiętny(18,3))/1024/1024 jako BackupSizeMb, rownum =row_number() over (partycja według bs.[nazwa_bazy_danych], kolejność typu według bs.[backup_finish_date] desc), LogicalDeviceName =bmf.[logiczna_nazwa_urządzenia], PhysicalDeviceName =bmf.[nazwa_urządzenia_fizycznego], bs.[nazwa_serwera], bs.[nazwa_użytkownika] Z msdb.dbo.backupset bs WEWNĘTRZNE POŁĄCZENIE msdb.dbo.backupmediafamily bmf ON [bs].[media_set_id] =[bmf].[media_set_id]) wybierz [nazwa_serwera] jako [ServerName], [database_name] as [DBName], [user_name] as [UserName], [backup_type] as [BackupType], [backup_start_date] as [BackupStartDate], [backup_finish_date] as [BackupFinishDate], [BackupSizeMb], -- nieskompresowany rozmiar [LogicalDeviceName], [PhysicalDeviceName], [first_lsn] as [FirstLSN], [last_lsn] as [LastLSN]from backup_ctewhere rownum =1;Wynik
W tym przewodniku przyjrzeliśmy się implementacji automatycznego procesu tworzenia kopii zapasowej na jednym serwerze, a następnie przywracania na innym (na przykład serwer testowy).
Ta metoda pozwala nam zautomatyzować proces tworzenia kopii zapasowych, sprawdzić kopie zapasowe poprzez ich przywrócenie i dostroić procesy pokazane powyżej.
Źródła:
Kopia zapasowa
Przywracanie
Kopia zapasowa
CHECKDB
SHRINKFILE
pliki_sys.master