Zaplanowane zadanie tworzenia kopii zapasowej nie zawsze wykonuje kopię zapasową wszystkich baz danych, mimo że zawsze mówi, że zadanie zakończyło się powodzeniem

9

Mam zadanie w SQL 2008, które uruchamia przechowywane proc do tworzenia kopii zapasowych wszystkich baz danych. Działa to codziennie za pośrednictwem zadania agenta serwera SQL.

Każdego dnia kończy się sukcesem, ale w niektóre dni kończy się sukcesem dopiero po utworzeniu kopii zapasowej kilku baz danych. Za każdym razem może być inna liczba baz danych. Większość dni z powodzeniem tworzy kopie zapasowe wszystkich baz danych, ale czasami 2 kopie zapasowe pomyślnie, czasem 5 itd.

Nie widzę żadnych błędów w historii zadań, przeglądarce zdarzeń ani logu serwera SQL.

Kopie zapasowe mają miejsce na dysku lokalnym, chociaż folder jest „połączeniem” z folderem na rozszerzalnym woluminie pamięci.

System operacyjny to Windows 2003 64bit z 64-bitową wersją Sql Server 2008 web jako maszyna wirtualna działająca na hoście Vmware ESXi 5.

Procedura składowana:

ALTER PROCEDURE [dbo].[backup_all_databases] 
@path VARCHAR(255)='c:\backups\'

AS

DECLARE @name VARCHAR(50) -- database name  
DECLARE @fileName VARCHAR(256) -- filename for backup  
DECLARE @fileDate VARCHAR(20) -- used for file name 
DECLARE @dbIsReadOnly sql_variant -- is database read_only?
DECLARE @dbIsOffline sql_variant -- is database offline?

DECLARE db_cursor CURSOR FOR  
SELECT name 
FROM master.dbo.sysdatabases 
WHERE name NOT IN ('tempdb')
AND version > 0 AND version IS NOT NULL

OPEN db_cursor   
FETCH NEXT FROM db_cursor INTO @name   

WHILE @@FETCH_STATUS = 0   
BEGIN   
SET @fileName = @path + @name + '.bak'

SET @dbIsReadOnly = (SELECT DATABASEPROPERTY(@name, 'IsReadOnly')) -- 1 = Read Only
SET @dbIsOffline = (SELECT DATABASEPROPERTY(@name, 'IsOffline')) -- 1 = Offline

IF (@dbIsReadOnly = 0 OR @dbIsReadOnly IS NULL) AND @dbIsOffline =0
BEGIN
    BACKUP DATABASE @name TO DISK = @fileName  WITH INIT
    WAITFOR DELAY '00:00:20'
END

FETCH NEXT FROM db_cursor INTO @name 
END   

CLOSE db_cursor   
DEALLOCATE db_cursor

Wszelkie sugestie proszę?

Andy Davies
źródło

Odpowiedzi:

9

Dodałbym bloki TRY / CATCH do obsługi błędów i rejestrowania ich. Baza danych może być w jednym użytkowniku, może zostać przywrócona lub cokolwiek innego.

Bez tego błędy mogą zostać przerwane w taki sposób, że żadne błędy nie są rejestrowane (instrukcja, partia, zakres, połączenie itp.)

Dzięki TRY / CATCH rejestrowane jest wszystko oprócz błędów kompilacji lub przerwania połączenia? ale wątpię, żeby tak było.

Używałbym również sys.databases, który zastępuje sysdatabases i czytał więcej flag:

-- declares etc

BEGIN TRY

    DECLARE db_cursor CURSOR FOR  
    SELECT name, state, user_access
    FROM sys.databases 
    WHERE name NOT IN ('tempdb')

    OPEN db_cursor   
    FETCH NEXT FROM db_cursor INTO @name, @state, @user_access

    WHILE @@FETCH_STATUS = 0   
    BEGIN   

        SET @fileName = @path + @name + '.bak'
        IF @state = 0 AND user_access = 0
        BEGIN
            BEGIN TRY
                BACKUP DATABASE @name TO DISK = @fileName  WITH INIT
            END TRY
            BEGIN CATCH
                -- log but do not rethrow so loop continues
            END CATCH
            WAITFOR DELAY '00:00:20'
        END
        ELSE
           --log user and/or state issues

        FETCH NEXT FROM db_cursor INTO @name 
    END   

    CLOSE db_cursor   
    DEALLOCATE db_cursor

END TRY
BEGIN CATCH
  -- some useful stuff here
END CATCH
gbn
źródło
+1 za poradę dotyczącą korzystania z sys.databases
Peter Schofield
2

Sprawdź błędy po poleceniu „backup”, wyślij swój własny e-mail pod kątem wykrytych błędów.

Daje to punkt wyjścia do sprawdzenia, co się dzieje, i gwarantuje ostrzeżenie o wszelkich problemach, dopóki problem nie zostanie rozwiązany.

Jimbo
źródło
2

Złóż zamówienie na kursor. Widziałem, że kursory do sys.databases mają „problemy”, gdy pozwalasz SQLowi na wybór kolejności zwracania danych. Porządek według nazwy powinien wystarczyć.

mrdenny
źródło
2

Czy kopia zapasowa jest uruchomiona w tym samym czasie co kopia zapasowa na taśmie lub inny proces kopiujący lub uzyskujący dostęp do plików kopii zapasowej? Jeśli tak, założę się, że nie zastąpi pliku, ponieważ jest w użyciu. Jeśli masz miejsce na wiele kopii zapasowych, możesz zmienić proc, aby dodać datownik do pliku wyjściowego, ale wtedy będziesz potrzebować procedury czyszczenia.

SqlACID
źródło
Nie, że jestem świadomy. Kopia zapasowa jest wykonywana lokalnie, a następnie rsync-ed kilka godzin później.
Andy Davies,
0

Wraz z wprowadzeniem SQL Server 2005 pętla kursora przez sysdatabases, a nawet sys.databases zmieniła się, więc nie była niezawodna - i tę zmianę zachowania można było zobaczyć również w sp_foreachdb.

Odkryłem, że zmiana rodzaju kursora pomogła (myślę, że było to szybkie przewijanie do przodu), ale ostatecznie przerzuciłem się na takie rozwiązania, jak rozwiązanie do tworzenia kopii zapasowych i konserwacji Oli Hallengren. Podobnie jak większość krytycznych rzeczy, takich jak kopie zapasowe, nadal musisz sprawdzić wszystkie bazy danych, aby upewnić się, że zostały one utworzone nawet przy użyciu tych potencjalnych rozwiązań - i oczywiście zrobiłeś to dobrze!

Typy kursorów: http://msdn.microsoft.com/en-us/library/ms378405(v=SQL.90).aspx

Rozwiązanie konserwacyjne Oli: http://ola.hallengren.com/

Peter Schofield
źródło
0

Miałem ten sam problem, zwłaszcza podczas tworzenia kopii zapasowych dużych baz danych.

@@fetch_statusjest zmienną GLOBALNĄ, więc może być zmieniona (ustawiona na 0) przez inny kursor niż twój. Rozwiązałem to, wykonując następujące czynności (w pseudokodzie):

create a temp table with dbNames
select top 1 in a variable (use order by)
while variable is null
do your thing

set variable = null
delete top 1(use order by)
select top 1 in a variable (use order by)
loop
Gerrit
źródło
-1

Próbowałem rozwiązać ten problem i wydaje się, że wiele razy użytkownicy opublikowali rozwiązanie, że jeśli unieważnisz deklarację kursora, zacznie ona działać. Przetestowałem to i tak, upewnia się tylko, że kursor deklaruje, że jest statyczny i zaczyna działać.

Faktem jest, że nie działa - Sprawdź ustawienie progu kursora na poziomie serwera - jeśli jest skonfigurowany jako -1, oznacza to, że wszystkie kursory zapełniają się synchronicznie, innymi słowy, podczas próby odczytania danych zestawu klawiszy kursora jest synchroniczny i wszystko jest próbowane czytać w tym samym czasie. Jeśli zmienimy tę wartość na 0, która każe serwerowi SQL wykonać asynchroniczną populację w prostych słowach, kursor może pobrać rekordy, podczas gdy zestaw kluczy będzie nadal zapełniany i zobaczysz, że po wykonaniu tej zmiany na poziomie serwera nigdy nie przegapisz żadnej bazy danych przy użyciu kursory.

Rozwiązania: Zadeklaruj statyczny kursor lub zmień ustawienie poziomu serwera „Próg kursora” na 0 z -1.

Dzięki, Gaurav Mishra | Senior DBA

użytkownik44716
źródło