Requête qui affiche les informations de sauvegarde (réussie et échouée) SQL Server

9

J'ai deux emplois qui sauvegardent deux bases de données différentes.
Le travail 1 sauvegarde DB1 Le
travail 2 sauvegarde DB2

DB1 ne parvient pas à sauvegarder en raison d'un espace insuffisant sur le lecteur 1, ce qui entraîne un échec du travail 1. Pour résoudre ce problème, je devais simplement ajouter de l'espace. Pas de biggie. On m'en a parlé aujourd'hui alors que le problème se pose depuis un mois. Ouais je sais que c'est fou mais c'est dev


Je souhaite obtenir un historique de sauvegarde complet pour DB1. Je sais que je peux récupérer des informations de sauvegarde réussies à partir de la table msdb.dbo.backupset mais je veux savoir s'il existe une requête qui affiche les sauvegardes ayant échoué pour une base de données.

Ma requête ci-dessous affiche l'historique de sauvegarde pour une base de données particulière du 12/31 / 13-1 / 27/14. Les informations incluent le serveur, le nom de la base de données, les heures de début et de fin de la sauvegarde, le temps total nécessaire pour la sauvegarde du dbs, la taille de la base de données et le nom du jeu de sauvegarde.

SELECT  
   distinct CONVERT(CHAR(100), SERVERPROPERTY('Servername')) AS Server, 
   msdb.dbo.backupset.database_name,  
   msdb.dbo.backupset.backup_start_date,  
   msdb.dbo.backupset.backup_finish_date, 
 CAST((DATEDIFF(second,  msdb.dbo.backupset.backup_start_date,msdb.dbo.backupset.backup_finish_date)) AS varchar)+ ' secs  ' AS [Total Time] ,

   Cast(msdb.dbo.backupset.backup_size/1024/1024 AS numeric(10,2)) AS 'Backup Size(MB)',   
   msdb.dbo.backupset.name AS backupset_name
FROM   msdb.dbo.backupmediafamily  
   INNER JOIN msdb.dbo.backupset ON msdb.dbo.backupmediafamily.media_set_id = msdb.dbo.backupset.media_set_id   
--Enter your database below
--and database_name = 'db_name_here'
and msdb.dbo.backupset.backup_start_date>'2013-12-31' and msdb.dbo.backupset.backup_start_date<'2014-01-27 23:59:59'
ORDER BY  
   msdb.dbo.backupset.database_name, 
   msdb.dbo.backupset.backup_start_date

Existe-t-il un moyen d'obtenir ces informations en modifiant mon code? Je suis capable de récupérer l'historique de JOB1 en exécutant une instruction sql qui s'exécute sur la table sysjobhistory et sysjob. Cela peut être long. Existe-t-il un moyen d'utiliser les tables sysjobhistory, sysjob, backupset et backupsetmediafamily dans msdb pour produire les résultats souhaités?

iamZel
la source

Réponses:

15

Malheureusement, backupsetne contient pas de sauvegardes ayant échoué, et je ne sais pas où msdbelles peuvent être stockées, à moins que vous ne puissiez vous en remettre à sysjobhistory, qui ne contient pas tout le temps (selon vos paramètres de rétention), et qui ignorerait tout les tentatives de sauvegarde qui ont été effectuées en dehors du contexte d'un travail et qui - dans le cas d'un travail qui sauvegarde de nombreuses bases de données - ne permettraient pas de différencier la base de données qui a réellement échoué, sauf si cela arrivait tôt dans le travail - c'est parce que la messagerie est assez verbeuse mais tronquée.

Si vous savez absolument que Job nseule la base de données est sauvegardée et que chaque échec de ce travail signifie que la base de données n'a pas été sauvegardée (car le travail peut également échouer après la réussite de la sauvegarde, par exemple en essayant de réduire ou d'effectuer une autre maintenance), alors vous pouvez utiliser une requête comme celle-ci:

DECLARE @job sysname, @db sysname;

SELECT @job = N'Job 1', @db = N'db_name';

SELECT  
   bs.database_name,  
   bs.backup_start_date,  
   bs.backup_finish_date, 
   [Total Time] = CAST((DATEDIFF(SECOND, bs.backup_start_date,bs.backup_finish_date))
     AS varchar(30))+ ' secs',
   CAST(bs.backup_size/1024/1024 AS decimal(10,2)) AS 'Backup Size(MB)',   
   h.[message]
FROM msdb.dbo.sysjobhistory AS h
INNER JOIN msdb.dbo.sysjobs AS j
ON h.job_id = j.job_id
AND h.step_id = 0
LEFT OUTER JOIN msdb.dbo.backupset AS bs
ON bs.database_name = @db
AND 
 ABS(DATEDIFF(SECOND, bs.backup_start_date, CONVERT(DATETIME,convert(char(8),h.run_date) 
   + ' ' + STUFF(STUFF(RIGHT('0'+CONVERT(char(6),h.run_time),6),3,0,':'),6,0,':')))) < 5
WHERE j.name = @job
ORDER BY bs.backup_start_date;

Oui, c'est vraiment moche, car sysjobhistorytoujours, dans SQL Server 2014 même, stocke run_dateet run_timesous forme d'entiers séparés. Je parie que celui qui a pris cette décision est toujours à l'arrière-plan des fléchettes partout dans le bâtiment 35. Il suppose également que la sauvegarde est la toute première étape du travail, d'où la comparaison date / heure plutôt moins que scientifique pour s'assurer que nous avons correctement corrélé la bonne instance du travail à la bonne instance de la sauvegarde. Oh, comment j'aimerais pouvoir repenser le schéma des sauvegardes et des jobs.

Si vous souhaitez une portée plus large en dehors du travail, vous pouvez rechercher les sauvegardes ayant échoué dans le journal des erreurs SQL Server (si elles n'ont pas été supprimées):

EXEC sp_readerrorlog 0, 1, 'BACKUP failed'; -- current
EXEC sp_readerrorlog 1, 1, 'BACKUP failed'; -- .1 (previous)
EXEC sp_readerrorlog 2, 1, 'BACKUP failed'; -- .2 (the one before that)
....

(Mais je ne connais pas de moyen agréable et facile d'incorporer cette sortie dans votre requête existante.)

Vous pouvez également corréler les sauvegardes réussies "manquantes" à partir de la trace par défaut, par exemple

DECLARE @path nvarchar(260);

SELECT 
   @path = REVERSE(SUBSTRING(REVERSE([path]), 
   CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM    sys.traces
WHERE   is_default = 1;

SELECT dt.DatabaseName, dt.StartTime, bs.backup_start_date, bs.backup_finish_date, 
  [Status] = CASE WHEN bs.backup_start_date IS NULL 
    THEN 'Probably failed'
    ELSE 'Seems like success'
  END
FROM sys.fn_trace_gettable(@path, DEFAULT) AS dt
LEFT OUTER JOIN msdb.dbo.backupset AS bs
ON dt.DatabaseName = bs.database_name
AND ABS(DATEDIFF(SECOND, dt.StartTime, bs.backup_start_date)) < 5
WHERE dt.EventClass = 115 -- backup/restore events
AND UPPER(CONVERT(nvarchar(max),dt.TextData)) LIKE N'BACKUP%DATABASE%'
--AND dt.DatabaseName = N'db_name' -- to filter to a single database
--AND bs.database_name = N'db_name'
ORDER BY dt.StartTime;

Bien sûr, cela dépend également des données de la trace par défaut, le nom de la base de données n'ayant pas changé, etc. données, mais tant que vous n'exécutez pas de sauvegardes en boucle, cela devrait être correct pour les yeux. J'ai essayé d'incorporer ces problèmes dans la requête.

Enfin, vous voudrez peut-être en utiliser un FULL OUTER JOIN, dans le cas où le jeu de sauvegarde a un historique plus long que la trace par défaut. Cela change [Status]légèrement la sémantique de .

Vous voudrez peut-être aussi essayer cette chose désagréable , même si je n'ai pas eu beaucoup de chance avec. Je n'ai pu voir que l'état actuel ou le plus récent, de sorte que cela n'a aidé que lorsque le travail a échoué lors de la dernière exécution, et - comme sysjobhistory- n'a pas été en mesure d'obtenir des informations sur les sauvegardes qui ont été tentées mais pas via un travail.

Aaron Bertrand
la source
Merci beaucoup pour l'explication détaillée mais je reçois une erreur lorsque j'exécute la première requête. Msg 139, niveau 15, état 1, ligne 0 Impossible d'attribuer une valeur par défaut à une variable locale. Msg 137, niveau 15, état 2, ligne 16 Doit déclarer la variable scalaire "@db"
iamZel
@iamZel alors vous êtes sur SQL Server 2005, pas SQL Server 2008.
Aaron Bertrand
Oui. J'ai oublié de mentionner cela. Je suis sur SQL2K5
iamZel
1
@iamZel La raison pour laquelle je pensais que vous étiez sur SQL Server 2008 est parce que vous avez marqué votre question avec cette version. Veuillez étiqueter soigneusement.
Aaron Bertrand
sp_readerrorlog est assez bon pour moi. Merci beaucoup Aaron
iamZel