How long since you ran DBCC CHECKDB?
If you’re not regularly looking for corrupt databases with DBCC CHECKDB, you’re putting your organization’s data at risk. I run DBCC CHECKDB
once per day, or as is reasonably possible. Typically, DBCC CHECKDB is setup as part of nightly maintenance.
Hopefully, you have SQL Server Agent jobs running DBCC CHECKDB, and when those jobs fail or report corruption, you’re all over fixing the problem. But, what if you create a database and forget to setup a scheduled DBCC CHECKDB
job? The script below reports when the last checkdb operation completed for each database, with a column showing “at-risk” databases with an “X”; that is databases where the last DBCC CHECKDB
occurred more than @MaxDaysWithoutCheckDB
days ago. Modify that parameter to suit your needs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
SET NOCOUNT ON; DECLARE @MaxDaysWithoutCheckDB int = 1; IF OBJECT_ID(N'tempdb..#Results') IS NOT NULL BEGIN DROP TABLE #Results; END CREATE TABLE #Results ( DatabaseName sysname NULL , IsOnline bit NULL , IsReadonly bit NULL , ParentObject varchar(100) NULL , [Object] varchar(100) NULL , [Field] varchar(100) NULL , [Value] varchar(100) NULL ); DECLARE @cmd nvarchar(1000); DECLARE @dbName sysname; DECLARE @IsOnline bit; DECLARE @IsReadonly bit; DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR SELECT DBCCCommand = 'DBCC DBINFO(''' + d.name + ''') WITH TABLERESULTS;' , DatabaseName = d.name , IsOnline = CONVERT(BIT, CASE WHEN d.state_desc = 'ONLINE' THEN 1 ELSE 0 END) , IsReadonly = d.is_read_only FROM sys.databases d WHERE d.name <> N'tempdb' AND d.name <> N'model' ORDER BY d.name; OPEN cur; FETCH NEXT FROM cur INTO @cmd, @dbName, @IsOnline, @IsReadonly; WHILE @@FETCH_STATUS = 0 BEGIN RAISERROR (@dbName, 0, 1) WITH NOWAIT; IF @IsOnline = 1 BEGIN INSERT INTO #Results (ParentObject, [Object], [Field], [Value]) EXEC sp_executesql @cmd; UPDATE #Results SET DatabaseName = @dbName , IsOnline = @IsOnline , IsReadonly = @IsReadonly WHERE DatabaseName IS NULL; END ELSE BEGIN INSERT INTO #Results (DatabaseName, IsOnline) VALUES (@dbName, @IsOnline) END FETCH NEXT FROM cur INTO @cmd, @dbName, @IsOnline, @IsReadonly; END CLOSE cur; DEALLOCATE cur; SELECT ServerName = @@SERVERNAME , DatabaseName = r.DatabaseName , LastKnownGoodDate = CONVERT(DATETIME, r.Value, 120) , AtRisk = CASE WHEN DATEDIFF(day, CONVERT(DATETIME, r.Value, 120), GETDATE()) > @MaxDaysWithoutCheckDB THEN 'X' ELSE '' END , IsDBOnline = r.IsOnline , IsReadonly = @IsReadonly FROM #Results r WHERE r.Field = 'dbi_dbccLastKnownGood' OR r.Field IS NULL; |
I’ve updated the above script to ensure compatibility with case-sensitive collations (thanks Konstantin Taranov for catching that!), and in response to the comment below from Robert, have added an Isreadonly
column to the output to show when a database is read-only.
Nice script!
Read only databases does not report as being checked. With this script, all read only databases will show at risk. It is not a problem with the script, but the fact that the the date checkdb was executed against a database is not updated due to the database being read only. However, a small enhancement to the script can allow easy visibility for databases that are read only.
Log shipped databases are another wrinkle with the script. This too is not a problem with the script,, but with how SQL Server updates the last time checkdb was executed against a database. The date shown is the date when the database was checked on the primary database, not when checked on the log shipped copy.
The enhanced version of the script is below.
Thanks for the suggestion, Robert! I’ve added a column to reflect the Read Only database property.
Hi, Hannah. Great thanks for your script, but it does not work on Case Sensitive Instances, I fixed it here https://github.com/ktaranov/sqlserver-kit/blob/master/Scripts/DBCC_CHECKDB_Latest_date.sql
Hi Konstantin – thanks for catching that! I was sure I’d ran it on my case sensitive servers, but apparently not. Anyway, I’ve updated the script so it should run properly on all servers, even those pesky case-sensitive ones!