Die geplante Sicherungsaufgabe sichert nicht immer alle Datenbanken, obwohl immer gesagt wird, dass der Job erfolgreich ist

9

Ich habe einen Job in SQL 2008, der einen gespeicherten Prozess ausführt, um alle Datenbanken zu sichern. Dies wird täglich über den SQL Server Agent-Job ausgeführt.

Es wird jeden Tag mit Erfolg beendet, aber an manchen Tagen wird es erst nach dem Sichern einiger Datenbanken mit Erfolg beendet. Es kann jedes Mal eine andere Anzahl von Datenbanken sein. An den meisten Tagen werden alle Datenbanken erfolgreich gesichert, manchmal jedoch 2 erfolgreich, manchmal 5 usw.

Ich sehe keine Fehler im Jobverlauf, in der Ereignisanzeige oder im SQL Server-Protokoll.

Sicherungen finden auf einer lokalen Festplatte statt, obwohl der Ordner eine "Verbindung" zu einem Ordner auf einem erweiterbaren Speichervolume ist.

Das Betriebssystem ist Windows 2003 64-Bit, auf dem SQL Server 2008 Web Edition 64-Bit als virtuelle Maschine ausgeführt wird, die auf dem Vmware ESXi 5-Host ausgeführt wird.

Gespeicherte Prozedur:

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

Irgendwelche Vorschläge bitte?

Andy Davies
quelle

Antworten:

9

Ich würde TRY / CATCH-Blöcke hinzufügen, um Fehler zu behandeln und sie zu protokollieren. Die Datenbank kann sich in einem einzelnen Benutzer befinden und wiederhergestellt werden oder was auch immer.

Ohne dies können Fehler so abgebrochen werden, dass keine Fehler protokolliert werden (Anweisung, Stapel, Bereich, Verbindung usw.)

Mit TRY / CATCH wird dann alles außer Kompilierungs- oder Verbindungsabbruchfehlern protokolliert? aber ich bezweifle, dass dies der Fall ist.

Ich würde auch sys.databases verwenden , das sysdatabases ersetzt, und weitere Flags lesen:

-- 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
quelle
+1 für den Rat, sys.databases zu verwenden
Peter Schofield
2

Suchen Sie nach dem Befehl "backup" nach Fehlern und senden Sie Ihre eigene E-Mail auf festgestellte Fehler.

Dies gibt Ihnen einen Ausgangspunkt, um zu sehen, was los ist, und garantiert Sie auf Probleme aufmerksam zu machen, bis Sie das Jobproblem gelöst haben.

Jimbo
quelle
2

Geben Sie eine Bestellung von auf den Cursor. Ich habe gesehen, dass Cursor auf sys.databases "Probleme" haben, wenn Sie SQL erlauben, die Reihenfolge auszuwählen, in der die Daten zurückgegeben werden. Die Bestellung nach Namen sollte ausreichen.

mrdenny
quelle
2

Wird die Sicherung gleichzeitig mit der Sicherung auf Band oder einem anderen Prozess ausgeführt, der die Sicherungsdateien kopiert oder darauf zugreift? Wenn ja, würde ich wetten, dass die Datei nicht überschrieben werden kann, weil sie verwendet wird. Wenn Sie Platz für mehrere Sicherungskopien haben, können Sie Ihren Prozess ändern, um der Ausgabedatei einen Datumsstempel hinzuzufügen. Dann benötigen Sie jedoch eine Bereinigungsroutine.

SqlACID
quelle
Nicht dass ich wüsste. Die Sicherung erfolgt lokal und einige Stunden später außerhalb des Standorts.
Andy Davies
0

Mit der Einführung von SQL Server 2005 schien sich die Cursorschleife durch sysdatabases und sogar sys.databases zu ändern, sodass sie nicht zuverlässig war - und diese Verhaltensänderung konnte auch bei sp_foreachdb beobachtet werden.

Ich fand es hilfreich, den Cursortyp zu ändern (ich glaube, es war ein schneller Vorlauf), aber letztendlich wechselte ich zu Lösungen wie der Backup- und Wartungslösung von Ola Hallengren. Wie bei den meisten wichtigen Dingen wie Backups müssen Sie immer noch alle Datenbanken überprüfen, um sicherzustellen, dass sie auch mit diesen potenziellen Lösungen gesichert werden - und Sie haben es offensichtlich so gut gemacht!

Cursortypen: http://msdn.microsoft.com/en-us/library/ms378405(v=SQL.90).aspx

Olas Wartungslösung: http://ola.hallengren.com/

Peter Schofield
quelle
0

Ich hatte das gleiche Problem, insbesondere beim Sichern großer DBs.

@@fetch_statusist eine GLOBAL-Variable, daher kann sie von einem anderen Cursor als Ihrem geändert (auf 0 gesetzt) ​​werden. Ich habe es folgendermaßen gelöst (im Pseudocode):

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
quelle
-1

Ich habe versucht, dieses Problem herauszufinden, und es scheint, dass Benutzer häufig die Lösung veröffentlicht haben, dass die Cursor-Deklaration funktioniert, wenn Sie sie unempfindlich machen. Also habe ich es getestet und ja, es stellt nur sicher, dass die Cursor-Deklaration statisch ist und es funktioniert.

Die Tatsache, für die dies fehlschlägt, ist: - Überprüfen Sie die Cursor-Schwellenwerteinstellung auf Serverebene. Wenn sie als -1 konfiguriert ist, bedeutet dies, dass alle Cursor synchron gefüllt werden, mit anderen Worten, während versucht wird, die Cursortasten-Set-Daten zu lesen. Dies ist synchron und alles wird versucht gleichzeitig lesen. Wenn wir diesen Wert auf 0 ändern, der SQL Server anweist, eine asynchrone Auffüllung in einfachen Worten durchzuführen, kann der Cursor die Datensätze abrufen, während der Schlüsselsatz noch gefüllt ist, und Sie werden sehen, dass Sie nach dieser Änderung auf Serverebene niemals eine Datenbank verpassen werden, die verwendet wird Cursor.

Lösungen: Deklarieren Sie entweder Cursor statisch oder ändern Sie die Serverebeneneinstellung "Cursor Threshold" von -1 auf 0.

Danke, Gaurav Mishra | Senior DBA

user44716
quelle