检查上次备份的时间

Hen*_*sen 6 sql-server restore dbcc-checkdb

Brent Ozar 于 2015-06-22 发表了一篇有趣的时事通讯;你如何管理 dbas 测量备份,他认为一个好的 DBA 应该检查什么时候

  • 上次备份完成
  • 上次恢复
  • 最后一个 CheckDB 完成

结果证明这对我来说是一个很好的锻炼。我不仅发现了两个没有备份的数据库,我还发现我们确实有一些数据库,我们从未检查过我们可以恢复备份。

所以; 我在答案部分为该任务提供了一种解决方案。我们约定数据库名称是唯一的,我的脚本列出了生产服务器和测试服务器,因此我可以比较它们。
你有更好的解决方案吗?

此致,

亨里克

Hen*_*sen 2

USE mydb

SET NOCOUNT on
BEGIN TRY
    DROP table #S 
END TRY
BEGIN CATCH
END CATCH

BEGIN TRY
    DROP TABLE  #Mytable
END TRY
BEGIN CATCH
END CATCH

BEGIN TRY
    DROP TABLE #DBInfoResults
END TRY
BEGIN CATCH
END CATCH

go

CREATE table #S ( server_name sysname, purpose VARCHAR(255), servertype VARCHAR(30) )
insert into #s
VALUES 
('myserver',  'Test', 'Smallserver'),
('mybigserver\dsa', 'Production', 'Data ware house'),
('myservertoo',  'Test', 'Data ware house')

declare  @Server_name sysname, @Purpose varchar(255)
declare @sql nvarchar(max) = N'',  @s varchar(21)='', @loopCounter int=0, @debug TINYINT=1

DECLARE Server_Cursor CURSOR
FOR
SELECT   s.server_name, s.purpose
FROM    #S s
order by 1

CREATE TABLE #Mytable (server_name sysname, database_name sysname, LastFullBackup DATE, LastIncrementalBackup DATE, comment VARCHAR(255), SizeInGB BIGINT, LastRestoreDate DATE, LastKnownGoodDBCCCheck DATE)
CREATE TABLE #DBInfoResults ([ParentObject] VARCHAR(512),[Object] VARCHAR(512),[Field] VARCHAR(512),[VALUE] VARCHAR(512))

OPEN Server_Cursor
FETCH NEXT FROM Server_Cursor INTO @Server_name, @Purpose
WHILE @@FETCH_STATUS = 0 BEGIN
    set @loopCounter +=1
    RAISERROR ('%i server: "%s"  ', 10 ,1, @Loopcounter, @Server_name) WITH NOWAIT

    select @sql = N'     
insert into #Mytable ( server_name, database_name, LastFullBackup, LastIncrementalBackup)
SELECT server_name, name, LastFullBackup, LastIncrementalBackup 
from OPENROWSET(''SQLNCLI10'', ''Server='+@Server_name+';Trusted_Connection=yes;'',
    ''SELECT server.server_name, d.name, FullBackup.LastFullBackup, IncBackup.LastIncrementalBackup 
    FROM sys.databases d
    OUTER APPLY (SELECT @@SERVERNAME AS server_name) AS server
    OUTER APPLY (
        SELECT TOP 1 B.backup_finish_date AS LastFullBackup
        FROM msdb.dbo.backupset B 
        WHERE TYPE=''''d''''
        AND server.server_name=B.server_name
        AND d.name=b.database_name
        ORDER BY B.backup_finish_date DESC 
    ) AS FullBackup
    OUTER APPLY (
        SELECT TOP 1 B.backup_finish_date AS LastIncrementalBackup
        FROM msdb.dbo.backupset B 
        WHERE TYPE=''''I''''
        AND server.server_name=B.server_name
        AND d.name=b.database_name
        ORDER BY B.backup_finish_date DESC 
    ) AS IncBackup
    WHERE STATE_DESC = ''''ONLINE''''
    AND name <> ''''tempdb'''' /* no backups, checkdbs needed */
    ORDER BY 1,2
    ''
    ) as a
    '
    if @loopCounter <= 1 IF @debug <> 0 select @sql
    begin try
        exec sp_executesql @sql
    end try
    begin CATCH
      print error_number()
      print ERROR_MESSAGE()
    end catch


    /* loop the databases found on this server */
    DECLARE @database_name sysname
    DECLARE db_Cursor CURSOR
    FOR
    SELECT database_name
    FROM  #Mytable H
    WHERE H.server_name=@Server_name
    order by 1

    OPEN db_Cursor
    FETCH NEXT FROM db_Cursor INTO @database_name
    WHILE @@FETCH_STATUS = 0 BEGIN
        select @sql = N'     
        UPDATE #Mytable 
        SET SizeInGB=(
            SELECT SizeInGB
            from OPENROWSET(''SQLNCLI10'', ''Server='+@Server_name+';Trusted_Connection=yes;'',
            ''
            SELECT SUM(CAST(size AS BIGINT))*8/1024/1024 as SizeInGB FROM ' + @database_name + '.sys.database_files DF
            ''
            ) as a
        )
        from #Mytable h
        where h.server_name=''' + @server_name + ''' and h.DataBase_name=''' + @database_name + '''

        '
        RAISERROR ('%i server: "%s" db: %s get Size', 10 ,1, @Loopcounter, @Server_name, @database_name) WITH NOWAIT
        if @loopCounter <= 1 IF @debug <> 0 select @sql
        begin try
            exec sp_executesql @sql
        end try
        begin CATCH

          print error_number()
          print ERROR_MESSAGE()
        end CATCH

        /* last restore date */
        select @sql = N'     
        UPDATE #Mytable 
        SET LastRestoreDate=(
            SELECT restore_date 
            FROM OPENROWSET(''SQLNCLI10'', ''Server='+@Server_name+';Trusted_Connection=yes;'',
            ''
            SELECT max(restore_date) as restore_date FROM msdb.dbo.restorehistory where destination_database_name=''''' + @database_name + '''''
            ''
            ) as a
        )
        from #Mytable h
        where h.server_name=''' + @server_name + ''' and h.DataBase_name=''' + @database_name + '''
        '

        RAISERROR ('%i server: "%s" db: %s get Restore date ', 10 ,1, @Loopcounter, @Server_name, @database_name) WITH NOWAIT
        if @loopCounter <= 1 IF @debug <> 0 select @sql
        begin try
            exec sp_executesql @sql
        end try
        begin CATCH

          print error_number()
          print ERROR_MESSAGE()
        end CATCH


        /* last DBCC */
        TRUNCATE TABLE #DBInfoResults
        select @sql = N'     
        Begin Try
          EXEC sys.sp_dropserver @server = ''myLinkedServer''
        End try
        begin catch
        end catch

        begin try
        EXEC sp_addlinkedserver @server=''myLinkedServer'', @srvproduct='''', @provider=''sqlncli'', @datasrc='''+@Server_name+''',  @location='''', @provstr='''', @catalog=''' + @database_name + '''  
        EXEC sp_addlinkedsrvlogin @rmtsrvname = ''myLinkedServer'', @useself = ''true''
        EXEC sp_serveroption ''myLinkedServer'', ''rpc out'', true;

        INSERT INTO #DBInfoResults
        EXEC (''DBCC DBINFO() WITH TABLERESULTS, NO_INFOMSGS'') at myLinkedServer

        UPDATE #Mytable 
        SET LastKnownGoodDBCCCheck=(SELECT value FROM #DBInfoResults where Field = ''dbi_dbccLastKnownGood'')
        from #Mytable h
        where h.server_name=''' + @server_name + ''' and h.DataBase_name=''' + @database_name + '''
        end try
        begin catch
          print error_number()
          print ERROR_MESSAGE()
        end catch
        EXEC sys.sp_dropserver @server = ''myLinkedServer''
        '

        RAISERROR ('%i server: "%s" dbcc: %s ', 10 ,1, @Loopcounter, @Server_name, @database_name) WITH NOWAIT
        if @loopCounter <= 1 select @sql
        begin try
            exec sp_executesql @sql
        end try
        begin CATCH

          print error_number()
          print ERROR_MESSAGE()
        end CATCH

        SET @loopCounter+=1
        FETCH NEXT FROM db_Cursor INTO @database_name
    END
    CLOSE db_Cursor ;
    DEALLOCATE db_Cursor ;

    FETCH NEXT FROM Server_Cursor INTO @Server_name, @Purpose
END
CLOSE Server_Cursor ;
DEALLOCATE Server_Cursor ;

UPDATE #Mytable SET Comment = 'Problem! '  FROM #Mytable H WHERE DATEDIFF(DAY, CASE WHEN h.LastIncrementalBackup>LastFullBackup THEN h.LastIncrementalBackup ELSE LastFullBackup END, GETDATE()) > 1
UPDATE #Mytable SET Comment = 'No backup required; structure in TFS.' WHERE database_name IN ('vdcasdw', 'mydbTemp', 'VTMChart', 'VTMFileStream', 'VTRArchive')
UPDATE #Mytable SET Comment = 'No backup required;' WHERE database_name LIKE '%ToBeDeleted'
UPDATE #Mytable SET Comment = 'No backup required; data in DWH.' WHERE database_name IN ('OperationalData')
UPDATE #Mytable SET Comment = 'No backup required; test server.'  FROM #Mytable H INNER JOIN #S S ON S.server_name = H.server_name WHERE Purpose IN ('test', 'Development')

/* list all checks */
SELECT top 10000 h.*, s.purpose, s.servertype FROM #Mytable H
INNER JOIN #S S ON S.server_name = H.server_name 
ORDER BY 1 DESC


/* run report on production servers */
SELECT H.server_name, H.database_name, COALESCE(CAST(H.LastFullBackup AS VARCHAR(30)), 'no backup exists!') AS LastFullBackup
, COALESCE(CAST(H.LastIncrementalBackup AS VARCHAR(30)), '') AS LastIncrementalBackup
, COALESCE(CAST(DATEDIFF(DAY, CASE WHEN h.LastIncrementalBackup>LastFullBackup THEN h.LastIncrementalBackup ELSE LastFullBackup END, GETDATE()) AS VARCHAR(30)), '') AS DaysSinceLastBackup
, COALESCE(comment, '') AS Comment 
, COALESCE(CAST(sizeinGB AS VARCHAR(30)), '') AS SizeinGB
, COALESCE(CAST(H2.LastRestoreDate AS VARCHAR(30)), 'Backup never tested!') AS LastRestoreDate
, COALESCE(CAST(DATEDIFF(DAY, h2.LastRestoreDate, GETDATE()) AS VARCHAR(30)), '') AS DaysSinceRestore
, CASE WHEN H2.LastKnownGoodDBCCCheck <> '1900-01-01' THEN (CAST(H2.LastKnownGoodDBCCCheck AS VARCHAR(30))) else 'A Database without DBCC CheckDB' END AS LastKnownGoodDBCCCheck
, CASE WHEN H2.LastKnownGoodDBCCCheck <> '1900-01-01' THEN (CAST(DATEDIFF(DAY, h2.LastKnownGoodDBCCCheck, GETDATE()) AS VARCHAR(30))) else '' END AS DaysSinceLastKnownGoodDBCCCheck
, h2.Purpose AS SystemThatExists
FROM #Mytable H
INNER JOIN #S S ON S.server_name = H.server_name
OUTER APPLY (
    SELECT MAX(LastKnownGoodDBCCCheck) AS LastKnownGoodDBCCCheck, MAX(LastRestoreDate ) AS LastRestoreDate,  utl.CommaListConcatenate(s3.Purpose) AS Purpose FROM #Mytable H3 
    INNER JOIN #S S3 ON S3.server_name = H3.server_name
    WHERE h.database_name=h3.database_name AND s3.servertype=s.servertype 
) AS h2
WHERE s.purpose='production'
ORDER BY 1,2
Run Code Online (Sandbox Code Playgroud)