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?

aSkywalker
źródło
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
Siergiej
źródło
1
Działa naprawdę świetnie, jeśli możesz uruchomić ten skrypt na oryginalnym serwerze, ale chcesz przywrócić go na innym serwerze!
realMarkusSchmidt
2
Skrypt pochodzi stąd mssqltips.com/sqlservertip/1243/…
Andrew Savinykh
@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.

JamesRyan
źródło
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

    }
Ben Curthoys
źródło
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,