La tâche de sauvegarde planifiée ne sauvegarde pas toujours toutes les bases de données bien que la tâche soit toujours réussie

9

J'ai un travail dans SQL 2008 qui exécute un proc stocké pour sauvegarder toutes les bases de données. Cela s'exécute quotidiennement via le travail de l'agent serveur SQL.

Il se ferme avec succès tous les jours, mais certains jours, il ne se termine avec succès qu'après avoir sauvegardé quelques bases de données. Il peut s'agir d'un nombre différent de bases de données à chaque fois. La plupart du temps, il sauvegarde avec succès toutes les bases de données, mais parfois 2 sauvegardes avec succès, parfois 5, etc.

Je ne vois aucune erreur dans l'historique des travaux, l'observateur d'événements ou le journal du serveur SQL.

Des sauvegardes ont lieu sur un disque local, bien que le dossier soit une "jonction" vers un dossier sur un volume de stockage extensible.

Le système d'exploitation est Windows 2003 64 bits exécutant Sql Server 2008 Web Edition 64 bits en tant que machine virtuelle exécutée sur l'hôte Vmware ESXi 5.

Procédure stockée:

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

Des suggestions s'il vous plait?

Andy Davies
la source

Réponses:

9

J'ajouterais des blocs TRY / CATCH pour gérer les erreurs et les enregistrer. La base de données peut être en mono-utilisateur, en cours de restauration ou autre.

Sans cela, les erreurs peuvent abandonner de manière à ce qu'aucune erreur ne soit enregistrée (instruction, lot, portée, connexion, etc.)

Avec TRY / CATCH, tout sauf les erreurs de compilation ou d'interruption de connexion est enregistré? mais je doute que ce soit le cas.

J'utiliserais également sys.databases qui remplace sysdatabases et lire plus de drapeaux:

-- 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
la source
+1 pour les conseils d'utilisation de sys.databases
Peter Schofield
2

Vérifiez les erreurs après la commande "sauvegarde", envoyez votre propre e-mail pour toute erreur détectée.

Cela vous donnera un point de départ pour voir ce qui se passe et vous garantira de vous alerter de tout problème jusqu'à ce que le problème soit résolu.

Jimbo
la source
2

Mettez une commande par sur le curseur. J'ai vu des curseurs sur sys.databases avoir des "problèmes" lorsque vous autorisez SQL à sélectionner l'ordre de retour des données. Commander par nom devrait suffire.

mrdenny
la source
2

La sauvegarde s'exécute-t-elle en même temps que la sauvegarde sur bande ou tout autre processus copiant ou accédant aux fichiers de sauvegarde? Si c'est le cas, je parie qu'il n'écrase pas le fichier car il est en cours d'utilisation. Si vous avez de la place pour plusieurs copies de sauvegarde, vous pouvez modifier votre proc pour ajouter un horodatage au fichier de sortie, mais vous aurez alors besoin d'une routine de nettoyage.

SqlACID
la source
Pas que je sache. La sauvegarde est effectuée localement puis rsync-ed hors site quelques heures plus tard.
Andy Davies
0

Avec l'introduction de SQL Server 2005, la boucle du curseur à travers sysdatabases et même sys.databases a semblé changer, ce qui n'était pas fiable - et ce changement de comportement pouvait également être observé avec sp_foreachdb.

J'ai trouvé utile de changer le type de curseur (je pense que c'était rapide), mais j'ai finalement opté pour des solutions telles que la solution de sauvegarde et de maintenance d'Ola Hallengren. Comme la plupart des choses critiques telles que les sauvegardes, vous devez toujours vérifier toutes les bases de données pour vous assurer qu'elles sont sauvegardées même avec ces solutions potentielles - et vous l'avez évidemment fait, si bien fait!

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

Solution de maintenance d'Ola: http://ola.hallengren.com/

Peter Schofield
la source
0

J'ai eu le même problème, en particulier lors de la sauvegarde de grandes bases de données.

@@fetch_statusest une variable GLOBALE, elle peut donc être modifiée (définie sur 0) par un autre curseur que le vôtre. Je l'ai résolu en faisant ce qui suit (en 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
la source
-1

J'ai essayé de comprendre ce problème et il semble que de nombreuses fois les utilisateurs ont publié la solution que si vous rendez la déclaration du curseur insensible, elle commence à fonctionner. Je l'ai donc testé et oui, il s'assure que le curseur est statique et commence à fonctionner.

Le fait pour lequel il échoue est - Vérifiez le paramètre de seuil du curseur au niveau du serveur - s'il est configuré sur -1, cela signifie que tous les curseurs sont remplis de manière synchrone en d'autres termes tout en essayant de lire les données de jeu de touches du curseur sont synchrones et tout est essayé de lire en même temps. Si nous changeons cette valeur en 0 qui indique au serveur SQL de faire une population asynchrone en mots simples, le curseur peut récupérer les enregistrements tandis que le jeu de clés sera toujours rempli et vous verrez qu'après avoir fait ce changement au niveau du serveur, vous ne manquerez plus aucune base de données utilisant curseurs.

Solutions: déclarez le curseur statique ou changez le paramètre de niveau du serveur "Cursor Threshold" à 0 de -1.

Merci, Gaurav Mishra | DBA senior

user44716
la source