web-dev-qa-db-fra.com

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

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 une défaillance de la tâche 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?

8
iamZel

Malheureusement, backupset ne contient pas de sauvegardes ayant échoué, et je ne connais aucun autre endroit dans msdb celles-ci peuvent être stockées, sauf si vous pouvez compter sur sysjobhistory, ce qui ne fonctionne pas ' ne contiennent pas tout le temps (en fonction de vos paramètres de rétention), et qui ignoreraient toutes les tentatives de sauvegarde 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 fourniraient pas de différenciation quelle base de données a échoué, à moins que cela ne se produise au début du travail - c'est parce que la messagerie est assez verbeuse mais tronquée.

Si vous savez absolument que Job n ne sauvegarde qu'une seule base de données 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 utilisez 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 NUMERIC(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(VARCHAR(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 sysjobhistory toujours, dans SQL Server 2014 même, stocke run_date et run_time sous forme d'entiers séparés. Je parie que celui qui a pris cette décision est toujours sur le fond 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 un peu 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 reconcevoir 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. Et malheureusement, la trace par défaut ne fait pas la différence entre les sauvegardes réussies et échouées, et l'heure de début ne correspondra pas précisément à la MSDB 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 souhaiterez peut-être utiliser un FULL OUTER JOIN là, dans le cas où le jeu de sauvegarde a un historique plus long que la trace par défaut. Cela change la sémantique de [Status] légèrement.

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

15
Aaron Bertrand