środa, 16 lutego 2011

restore plan


Wszyscy są zgodni, że robienie backupu bazy i logów jest bardzo ważnym zadaniem administratora baz danych, jeżeli chodzi o backup logu powinien on być robiony jak najczęściej bo wtedy możemy zminimalizować straty w przypadku awarii.
Czasami słyszę opinie, że ktoś nie robi backupu logu częściej niż co godzinę bo by miał potem problem z odtworzeniem ciągłości backupu.
Przy odtwarzaniu bazy po awarii pomocna może się okazać procedura.


CREATE PROCEDURE rk_restore_plan
                              @db_name SYSNAME
                             ,@restore_to_datetime  DATETIME --= GETDATE()

AS
/*
rk_restore_plan 'test','2011-02-16 13:47'
*/

SET NOCOUNT ON
DECLARE @server_name NVARCHAR(512)
DECLARE @first_full_backupset_id INTEGER
DECLARE @first_full_backup_startdate DATETIME
DECLARE @print TABLE(id INT IDENTITY(1,1) PRIMARY KEY, tekst   VARCHAR(255)) 
           
CREATE TABLE #plan(backup_set_id INTEGER NOT NULL,type CHAR(1),stopat_time DATETIME ,used BIT)

SET @server_name = @@SERVERNAME

SELECT @first_full_backupset_id = backupset_outer.backup_set_id
      ,@first_full_backup_startdate = backupset_outer.backup_start_date
  FROM msdb.dbo.backupset backupset_outer
 WHERE backupset_outer.database_name = @db_name
   AND backupset_outer.server_name = @server_name
   AND backupset_outer.type = 'D'   
   AND backupset_outer.backup_start_date =
(  SELECT MAX(backupset_inner.backup_start_date)
   FROM msdb.dbo.backupset backupset_inner
   WHERE backupset_inner.database_name = backupset_outer.database_name
      AND backupset_inner.server_name = @server_name
    AND backupset_inner.type = backupset_outer.type
    AND backupset_inner.backup_start_date <= @restore_to_datetime
    AND backupset_inner.is_copy_only = 0 )
   AND backupset_outer.is_copy_only = 0

INSERT #plan
SELECT backup_set_id,type,backup_finish_date,1         
  FROM msdb.dbo.backupset
WHERE msdb.dbo.backupset.backup_set_id = @first_full_backupset_id
  AND msdb.dbo.backupset.server_name = @server_name

INSERT #plan
SELECT backup_set_id,type,backup_finish_date,1                        
  FROM msdb.dbo.backupset
 WHERE msdb.dbo.backupset.database_name = @db_name
   AND msdb.dbo.backupset.server_name = @server_name
   AND msdb.dbo.backupset.type IN ('I', 'L') 
   AND msdb.dbo.backupset.backup_start_date >= @first_full_backup_startdate
  
UPDATE #plan
  SET used =0
WHERE stopat_time>@restore_to_datetime

UPDATE #plan
  SET used =1
WHERE type ='L'
  AND backup_set_id IN(SELECT TOP (1) backup_set_id FROM #plan
                                    WHERE used =0
                                   ORDER BY backup_set_id)



INSERT @print
SELECT
'RESTORE '+ CASE BS.type WHEN  'D' THEN 'DATABASE '
                                  WHEN  'I' THEN 'DATABASE '
                                    WHEN  'L' THEN 'LOG '
                                    ELSE 'ERROR' END
+QUOTENAME(BS.database_name) + ' FROM  DISK = N'''
+MF.physical_device_name +''' WITH FILE = '+CAST (BS.position AS VARCHAR(5))
+' , NORECOVERY, REPLACE, STATS = 10'
+ CASE WHEN BST.stopat_time >@restore_to_datetime THEN ', STOPAT = N'''+CONVERT(VARCHAR(20),@restore_to_datetime,126)+'''' ELSE '' END
FROM msdb..backupset BS
INNER JOIN #plan BST
ON BS.backup_set_id = BST.backup_set_id
INNER JOIN msdb..backupmediafamily MF
on BS.media_set_id=MF.media_set_id
WHERE used =1
ORDER BY BST.backup_set_id
INSERT @print
SELECT  'RESTORE DATABASE '+QUOTENAME(@db_name) + ' WITH RECOVERY'

SELECT tekst FROM @print
ORDER BY id


Zwraca ona wszystkie kopie które trzeba odtworzyć żeby przywrócić bazę do konkretnego punktu w czasie.
Dla bezpieczeństwa nie są uruchamiane skrypty a tylko zwracane polecenia do wykonania.
Skrypt zakłada, że baza jest odtwarzana w te samo miejsce na dyskach, obsługuje
  • backup full
  • backup differential
  • backup log
  • backup copy_only
  • backupy do pliku i devices
  • backupy dopisujące i nadpisujące media set

2 komentarze: