Kopie zapasowe dziennika transakcji SQL Server: sprawdź, czy dziennik ogona następuje po ostatniej znanej kopii zapasowej dziennika

11

Używamy programu SQL Server z pełnym trybem odzyskiwania. Biorąc pod uwagę pełną kopię zapasową i serię kopii zapasowych dziennika, chcielibyśmy móc sprawdzić, czy łańcuch dziennika jest kompletny od ostatniej pełnej kopii zapasowej do bieżącego dziennika ogona. (Bez faktycznego przywracania tych kopii zapasowych; celem jest przetestowanie spójności kopii zapasowych).

Wiem już, jak to zrobić dla istniejących kopii zapasowych: używając PRZYWRACANIA HEADERONLY otrzymuję FirstLSN i LastLSN każdego pliku, który można porównać dla kolejnych plików, w celu ustalenia, czy są one kompatybilne.

Nie wiem jednak, jak sprawdzić, czy dziennik ogona następuje po ostatniej kopii zapasowej dziennika.

Gdybym miał FirstLSN dziennika ogona, mógłbym porównać go do LastLSN ostatniej kopii zapasowej dziennika. Ale jak mogę uzyskać FirstLSN dziennika ogona?

Potrzebuję rozwiązania, które działa od SQL Server 2005 w górę (najlepiej przy użyciu t-sql). Do tej pory szukałem Google bezskutecznie. Btw. Po raz pierwszy opublikowałem to na stackoverflow; ale migrowałem go tutaj, ponieważ został tam oznaczony jako nie na temat.

EDYTOWAĆ

Wypróbowałem dwa dostarczone rozwiązania na małym przykładzie (SQL Server 2005, 9.0.5057):

BACKUP DATABASE TestDb TO DISK = 'C:\temp\backup test\Full.bak' 

-- fire some update queries

BACKUP LOG TestDb TO DISK =  'C:\temp\backup test\Log1.bak' 

-- fire both queries from the provided answers: 
-- Martin Smith's answer yields: 838886656088920652852608
-- Shawn Melton's answer yields: 46000000267600001

RESTORE HEADERONLY FROM DISK = 'C:\temp\backup test\Log1.bak'  
-- yields: 46000000267600001

Wygląda na to, że pierwszy jest wyłączony o kilka rzędów wielkości.

Następnie wykonałem ten sam test na SQL 2008 SP1 (10.00.2531), gdzie oba zapytania dały poprawną odpowiedź.

Andreas
źródło
Prowadziłem badania, ponieważ to interesujące pytanie, ale nie docieram zbyt daleko. Nie jestem pewien, czy SQL obsługuje to od razu po wyjęciu z pudełka.
Katherine Villyard
1
Jestem pewien, że istnieje sposób, aby to sprawdzić, być może użycie LSN nie jest sposobem na to. Zaliczę to pytanie za kilka godzin, to pytanie wymaga więcej widoków.

Odpowiedzi:

12

Zwróciłem się do mojej kopii SQL Server 2008 Wewnętrzne i DMV sys.database_recovery_status został wskazany, aby znaleźć pierwszą LSN następnej kopii zapasowej dziennika. Które przechodząc przez BOL kolumna last_log_backup_lsnzapewnia:

Numer sekwencji dziennika najnowszej kopii zapasowej dziennika. Jest to koniec LSN poprzedniej kopii zapasowej dziennika i początkowy LSN następnej kopii dziennika.
NULL = Brak kopii zapasowej dziennika. Baza danych jest w trybie offline lub baza danych nie chce się uruchomić.

Wystarczy wspomnieć, że Kalen również podnosi kwestię, że otrzymasz wartość NULL, jeśli baza danych jest w trybie odzyskiwania SIMPLE (tryb automatycznego wyłączania) lub jeśli nie ma kopii zapasowej dziennika.

Ale jak mogę uzyskać FirstLSN dziennika ogona?

Bez faktycznego tworzenia kopii zapasowej dziennika ogona bazy danych (nie ma instancji testowej do wypróbowania tego), można logicznie stwierdzić, że wartość zwrócona w wymienionej kolumnie byłaby pierwszą LSN kolejnej kopii zapasowej dziennika, w twoim przypadku ogon.

Wykonanie następującego zwróci wartość, której według mnie szukasz:


SELECT 
   last_log_backup_lsn
FROM 
   sys.database_recovery_status
WHERE 
   databse_id = DB_ID('MyDb')

Ten DMV jest dostępny począwszy od SQL 2005.

EDYCJA
O ile nie przeczytasz linku BOL, pamiętaj, że ten DMV zwróci tylko wartości do baz danych, które są w trybie online, lub otwarte, gdy BOL odwołuje się do niego. Jeśli wystąpi awaria, która wymaga wykonania kopii zapasowej dziennika bazy danych bazy danych, nie będzie można zweryfikować tej wartości za pomocą powyższego kodu, chyba że baza danych jest dostępna; co w przypadku awarii prawdopodobnie nie byłoby.


źródło
Wynik tego zapytania wydaje się być poprawny.
Andreas
Z pewnością wygląda dla mnie poprawnie. Last_log_backup_lsn jest równy first_lsn ogona dziennika. Jeśli więc masz plik dziennika do przywrócenia z last_lsn równym last_log_backup_lsn z kodu Shawna, to wiesz, że masz kopię zapasową aż do dziennika ogona. (Oczywiście jest to gwarantowane tylko w momencie zapytania, w następnym momencie można rozpocząć tworzenie nowej kopii zapasowej dziennika.)
RLF
@RLF dodał dodatkową notatkę, ponieważ byłoby to również prawdą, jeśli baza danych nie jest dostępna. W rzeczywistości nie jest to realne rozwiązanie, gdy trzeba wdrożyć plan odzyskiwania po awarii. Przeznaczony wyłącznie do ćwiczeń na stole lub testowania planu.
6

Powinno to zrobić coś takiego.

WITH LSN_CTE
AS
(
SELECT TOP 1
       LEFT( LogRecords.[Current LSN], 8 )          AS Part1,
       SUBSTRING( LogRecords.[Current LSN], 10, 8 ) AS Part2,
       RIGHT( LogRecords.[Current LSN], 4 )         AS Part3
FROM   sys.fn_dblog(NULL,NULL) AS LogRecords
ORDER BY [Current LSN]
)
SELECT CAST( CAST( CONVERT( varbinary, Part1, 2 ) AS int ) AS varchar ) +
       RIGHT( '0000000000' + CAST( CAST( CONVERT( varbinary, Part2, 2 ) AS int ) AS varchar ), 10 ) +
       RIGHT( '00000'      + CAST( CAST( CONVERT( varbinary, Part3, 2 ) AS int ) AS varchar ), 5 ) AS [Converted LSN]
FROM   LSN_CTE

Używanie kodu konwersji dziesiętnej z tego artykułu .

ORDER BY [Current LSN]Może okazać się całkowicie niepotrzebne koszty. Nie jestem pewny. Wynik tej funkcji zawsze wydaje się być w kolejności LSN i myślę, że po prostu czyta dziennik sekwencyjnie, ale na wszelki wypadek ...

Martin Smith
źródło
@MartinSmith: fn_dblognie wydaje się być zbyt dobrze udokumentowany. Zakładam, że jego wyniki zawsze zachowują się dla bieżącej bazy danych (ponieważ nie ma jej WHERE DbName = 'XXX'we fragmencie)?
Andreas
@Andreas - Tak, jest to nieudokumentowane. I tak, zwraca informacje z dziennika bieżącej bazy danych.
Martin Smith
zobacz moją edycję pierwotnego pytania. Liczba zwrócona przez Twój fragment jest znacznie większa niż LSN z ostatnich kopii zapasowych tego samego DB.
Andreas
@Andreas - Dziwne. Próbowałem tylko na jednym testowym DB i działało poprawnie. Nie jestem pewien, gdzie jest błąd. Na jakiej wersji SQL Server używasz tego? CONVERTStylu parametr 2może być problem.
Martin Smith
(Mimo wszystko odpowiedź Shawna wydaje się zdecydowanie lepsza od tej)
Martin Smith