Jak przywrócić partię dzienników transakcji zamiast pojedynczo


12

Mam bazę danych SQL Server, która tworzy kopie zapasowe dzienników transakcji co 10 minut, z nocną pełną kopią zapasową.

Używając SQL 2008 Management studio wydaje się, że musimy wybierać każdy dziennik transakcji jeden po drugim. Czy jest jakiś sposób wskazania go na katalog?

Zastanawiam się nad uruchomieniem różnicowej kopii zapasowej kilka razy dziennie, co może zrekompensować część tego, ale przechodzenie jeden po drugim przez dziesiątki / setki plików wydaje się dość czasochłonne. Pisanie kodu, aby spróbować napisać skrypt, wydaje się zbyt odbiegające od naszych podstawowych kompetencji.

Jeśli SQL Server Management Studio nie ma szybszego sposobu, być może dostępne jest narzędzie innej firmy?


Tak, jeśli wszystkie możliwe mechanizm nie działa wtedy, że lepiej wziąć pomoc od Log SQL Recovery Tool sqlserverlogexplorer.com/restore
Jason Clarke

Odpowiedzi:


11

Nie ma sposobu, aby określić grupę kopii zapasowych dziennika transakcji (folder oк) do przywrócenia w SQL Server Management studio.

Ale wszystkie informacje na temat operacji tworzenia kopii zapasowych programu SQL Server można znaleźć w bazie danych MSDB (zestaw kopii zapasowych tabeli i powiązane).

Oto skrypt do generowania poleceń programu SQL Server do przywracania bazy danych z kopii zapasowej i stosowania kopii zapasowych wszystkich dzienników transakcji wykonanych od ostatniej pełnej kopii zapasowej bazy danych. Myślę, że to powinno ci pomóc.

DECLARE @databaseName sysname
DECLARE @backupStartDate datetime
DECLARE @backup_set_id_start INT
DECLARE @backup_set_id_end INT

-- set database to be used
SET @databaseName = '<your_database_name_here>' 

SELECT @backup_set_id_start = MAX(backup_set_id) 
FROM  msdb.dbo.backupset 
WHERE database_name = @databaseName AND type = 'D'

SELECT @backup_set_id_end = MIN(backup_set_id) 
FROM  msdb.dbo.backupset 
WHERE database_name = @databaseName AND type = 'D'
AND backup_set_id > @backup_set_id_start

IF @backup_set_id_end IS NULL SET @backup_set_id_end = 999999999

SELECT backup_set_id, 'RESTORE DATABASE ' + @databaseName + ' FROM DISK = ''' 
               + mf.physical_device_name + ''' WITH NORECOVERY'
FROM    msdb.dbo.backupset b,
           msdb.dbo.backupmediafamily mf
WHERE    b.media_set_id = mf.media_set_id
           AND b.database_name = @databaseName
          AND b.backup_set_id = @backup_set_id_start
UNION
SELECT backup_set_id, 'RESTORE LOG ' + @databaseName + ' FROM DISK = ''' 
               + mf.physical_device_name + ''' WITH NORECOVERY'
FROM    msdb.dbo.backupset b,
           msdb.dbo.backupmediafamily mf
WHERE    b.media_set_id = mf.media_set_id
           AND b.database_name = @databaseName
          AND b.backup_set_id >= @backup_set_id_start AND b.backup_set_id < @backup_set_id_end
          AND b.type = 'L'
UNION
SELECT 999999999 AS backup_set_id, 'RESTORE DATABASE ' + @databaseName + ' WITH RECOVERY'
ORDER BY backup_set_id

1
Działa naprawdę świetnie, jeśli możesz uruchomić ten skrypt na oryginalnym serwerze, ale chcesz przywrócić go na innym serwerze!
realMarkusSchmidt


@sergey: powinieneś przypisywać skrypty, które ściągasz z sieci! : mssqltips.com/sqlservertip/1243/…
Mitch Wheat


4

potrzebujesz tylko listy instrukcji SQL, takich jak ...

RESTORE LOG AdventureWorks FROM DISK = 'C:\AdventureWorks_1.TRN' WITH NORECOVERY
GO
RESTORE LOG AdventureWorks FROM DISK = 'C:\AdventureWorks_2.TRN'
GO

Możesz więc stworzyć skrypt VB, który z łatwością wygeneruje ten kod SQL z danego folderu. Oto przykład http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/restoring-multiple-transaction-log-backu

Po utworzeniu kodu SQL wystarczy sprawdzić, czy wygląda poprawnie i uruchomić go.


1

Nie chciałem stosować przyjętej odpowiedzi w oparciu o SQL, ponieważ nie chciałem włączać rozszerzonych procedur przechowywanych. Napisałem więc skrypt PowerShell, aby to zrobić.

Wskazujesz go na folder, a on generuje skrypt na podstawie najnowszej pełnej kopii zapasowej i wszystkich kolejnych kopii dziennika transakcji.

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")

    $foldername = New-Object System.Windows.Forms.FolderBrowserDialog
    $foldername.rootfolder = "MyComputer"
    $foldername.ShowNewFolderButton = $false
    $foldername.SelectedPath = "E:\DatabaseBackups"

    if($foldername.ShowDialog() -eq "OK") {
        $backupPath = Get-Item($foldername.SelectedPath)    
        $databaseName = $backupPath.Name

        Write-Host($backupPath)
        Write-Host($databaseName)

        $transactionLogFiles = New-Object System.Collections.ArrayList;
        $outputFile = "Restore Database - Script.sql"
        $backupFile;


        foreach ($file in  get-childitem ($backupPath) | sort-object LastWriteTime -descending)
        {
            if ($file.Extension -eq '.trn')
            {
                [void]$transactionLogFiles.Add($file);
            }
            elseif ($file.Extension -eq '.bak')
            {
                $backupFile = $file;
                break;
            }
        }


        Set-Content $outputFile ""

        Add-Content $outputFile "USE master"
        Add-Content $outputFile "ALTER DATABASE $databaseName SET SINGLE_USER WITH ROLLBACK AFTER 5"
        Add-Content $outputFile "RESTORE DATABASE $databaseName FROM DISK = '$($backupFile.FullName)' WITH NORECOVERY";

        foreach ($file in $transactionLogFiles | sort-object LastWriteTime)
        {
            Add-Content $outputFile "RESTORE LOG $databaseName FROM DISK = '$($file.FullName)' WITH NORECOVERY";    
        }

        Add-Content $outputFile "RESTORE DATABASE $databaseName WITH RECOVERY";
        Add-Content $outputFile "ALTER DATABASE $databaseName SET MULTI_USER";
        Add-Content $outputFile "USE $databaseName" 

        Write-Host("Script generated at $outputFile");
        Write-Host "Press any key to continue ..."
        $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
        Invoke-Item $outputFile

    }

Dziękuję Ci! Właśnie uratowałeś mój boczek przed gorącym ogniem ... msdb był uszkodzony, więc musiałem go przywrócić z kopii zapasowej i nie miał informacji o łańcuchu dziennika. Twój skrypt uratował mnie przed ręcznym budowaniem skryptów przywracania dziennika transakcji na podstawie nazwy pliku!
agrath

Co jeśli potrzebujesz tylko jednej bazy danych i wszystkich dzienników transakcji? Co musisz zmienić w skrypcie?
user493592,

Tak właśnie działa. Jedna baza danych (najnowsza) i wszystkie dzienniki transakcji od tego czasu. Nie ma sensu patrzeć na dzienniki transakcji sprzed pełnej kopii zapasowej.
Ben Curthoys,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.